diff --git a/vendor/htree/.cvsignore b/vendor/htree/.cvsignore new file mode 100644 index 0000000..f63e5e5 --- /dev/null +++ b/vendor/htree/.cvsignore @@ -0,0 +1,3 @@ +index.html +README.html +doc diff --git a/vendor/htree/Makefile b/vendor/htree/Makefile new file mode 100644 index 0000000..74d858e --- /dev/null +++ b/vendor/htree/Makefile @@ -0,0 +1,21 @@ +RUBY=ruby +RD2HTML=rd2 -r rd/rd2html-lib.rb + +all: README.html doc/index.html + +README.html: README.rd + $(RD2HTML) --html-title='htree - HTML/XML tree library' -o README README.rd + +check test: + $(RUBY) -I. test-all.rb + +install: + $(RUBY) install.rb + +.PHONY: check test all install + +RB = htree.rb htree/modules.rb $(wildcard htree/[a-l]*.rb) $(wildcard htree/[n-z]*.rb) +doc/index.html: $(RB) + rm -rf doc + rdoc $(RB) + diff --git a/vendor/htree/README.rd b/vendor/htree/README.rd new file mode 100644 index 0000000..f868278 --- /dev/null +++ b/vendor/htree/README.rd @@ -0,0 +1,48 @@ += htree - HTML/XML tree library + +htree provides a tree data structure which represent HTML and XML data. + +== Features + +* Permissive unified HTML/XML parser +* byte-to-byte round-tripping unparser +* XML namespace support +* Dedicated class for escaped string. This ease sanitization. +* HTML/XHTML/XML generator +* template engine +* recursive template expansion +* converter to REXML document + +== Home Page + +(()) + +== Download + +* (()) + +== Install + + % ruby install.rb + +== Reference Manual + +(()) + +== Usage Example + +Following two-line script convert HTML to XHTML. + + require 'htree' + HTree(STDIN).display_xml + +The conversion method to REXML is provided as to_rexml. + + HTree(...).to_rexml + +== License + +Ruby's + +== Author +Tanaka Akira diff --git a/vendor/htree/htree.rb b/vendor/htree/htree.rb new file mode 100644 index 0000000..a797d54 --- /dev/null +++ b/vendor/htree/htree.rb @@ -0,0 +1,97 @@ +# +# = htree.rb +# +# HTML/XML document tree +# +# Author:: Tanaka Akira +# +# == Features +# +# - Permissive unified HTML/XML parser +# - byte-to-byte round-tripping unparser +# - XML namespace support +# - Dedicated class for escaped string. This ease sanitization. +# - XHTML/XML generator +# - template engine: link:files/htree/template_rb.html +# - recursive template expansion +# - REXML tree generator: link:files/htree/rexml_rb.html +# +# == Example +# +# The following one-liner prints parsed tree object. +# +# % ruby -rhtree -e 'pp HTree(ARGF)' html-file +# +# The following two-line script convert HTML to XHTML. +# +# require 'htree' +# HTree(STDIN).display_xml +# +# The conversion method to REXML is provided as to_rexml. +# +# HTree(...).to_rexml +# +# == Module/Class Hierarchy +# +# * HTree +# * HTree::Name +# * HTree::Context +# * HTree::Location +# * HTree::Node +# * HTree::Doc +# * HTree::Elem +# * HTree::Text +# * HTree::XMLDecl +# * HTree::DocType +# * HTree::ProcIns +# * HTree::Comment +# * HTree::BogusETag +# * HTree::Error +# +# == Method Summary +# +# HTree provides following methods. +# +# - Parsing Methods +# - HTree(html_string) -> HTree::Doc +# - HTree.parse(input) -> HTree::Doc +# +# - Generation Methods +# - HTree::Node#display_xml -> STDOUT +# - HTree::Node#display_xml(out) -> out +# - HTree::Node#display_xml(out, encoding) -> out +# - HTree::Text#to_s -> String +# +# - Template Methods +# - HTree.expand_template{template_string} -> STDOUT +# - HTree.expand_template(out){template_string} -> out +# - HTree.expand_template(out, encoding){template_string} -> out +# - HTree.compile_template(template_string) -> Module +# - HTree{template_string} -> HTree::Doc +# +# - Traverse Methods +# - HTree::Elem#attributes -> Hash[HTree::Name -> HTree::Text] +# - HTree::Elem::Location#attributes -> Hash[HTree::Name -> HTree::Location] +# +# - Predicate Methods +# - HTree::Traverse#doc? -> true or false +# - HTree::Traverse#elem? -> true or false +# - HTree::Traverse#text? -> true or false +# - HTree::Traverse#xmldecl? -> true or false +# - HTree::Traverse#doctype? -> true or false +# - HTree::Traverse#procins? -> true or false +# - HTree::Traverse#comment? -> true or false +# - HTree::Traverse#bogusetag? -> true or false +# +# - REXML Tree Generator +# - HTree::Node#to_rexml -> REXML::Child + +require 'htree/parse' +require 'htree/extract_text' +require 'htree/equality' +require 'htree/inspect' +require 'htree/display' +require 'htree/loc' +require 'htree/traverse' +require 'htree/template' +require 'htree/rexml' diff --git a/vendor/htree/htree/container.rb b/vendor/htree/htree/container.rb new file mode 100644 index 0000000..da7da8b --- /dev/null +++ b/vendor/htree/htree/container.rb @@ -0,0 +1,8 @@ +require 'htree/modules' + +module HTree::Container + # +children+ returns children nodes as an array. + def children + @children.dup + end +end diff --git a/vendor/htree/htree/context.rb b/vendor/htree/htree/context.rb new file mode 100644 index 0000000..cf54b82 --- /dev/null +++ b/vendor/htree/htree/context.rb @@ -0,0 +1,69 @@ +module HTree + class Context + # :stopdoc: + DefaultNamespaces = {'xml'=>'http://www.w3.org/XML/1998/namespace'} + DefaultNamespaces.default = "" + DefaultNamespaces.freeze + # :startdoc: + + # The optional argument `namespaces' should be a hash or nil. + # HTree::DefaultNamespaces is used if nil is specified. + # + # If it is a hash, its key should be nil or a string. + # nil means default namespace. + # The string means some prefix which must not be empty. + # + # The hash value should be a string. + # The empty string "" means unbound namespace. + def initialize(namespaces=nil) + namespaces ||= DefaultNamespaces + namespaces.each_pair {|k, v| + check_namespace_prefix(k) + check_namespace_uri(v) + } + namespaces = namespaces.dup.freeze unless namespaces.frozen? + @namespaces = namespaces + end + attr_reader :namespaces + + # return a namespace URI corresponding to _prefix_. + # It returns nil if _prefix_ is not defined. + def namespace_uri(prefix) + @namespaces[prefix] + end + + # generate a new Context object which namespaces are substituted by + # a hash _declared_namespaces_. + def subst_namespaces(declared_namespaces) + namespaces = @namespaces.dup + declared_namespaces.each {|k, v| + check_namespace_prefix(k) + check_namespace_uri(v) + namespaces[k] = v + } + if namespaces == @namespaces + self + else + Context.new(namespaces) + end + end + + private + def check_namespace_prefix(k) + unless (String === k && !k.empty?) || k == nil + raise ArgumentError, "invalid namespace prefix: #{k.inspect}" + end + end + + def check_namespace_uri(v) + unless String === v + raise ArgumentError, "invalid namespace URI: #{v.inspect}" + end + end + end + + # :stopdoc: + DefaultContext = Context.new + HTMLContext = DefaultContext.subst_namespaces(nil=>"http://www.w3.org/1999/xhtml") + # :startdoc: +end diff --git a/vendor/htree/htree/display.rb b/vendor/htree/htree/display.rb new file mode 100644 index 0000000..61d12e9 --- /dev/null +++ b/vendor/htree/htree/display.rb @@ -0,0 +1,46 @@ +require 'htree/output' + +module HTree + module Node + # HTree::Node#display_xml prints the node as XML. + # + # The first optional argument, out, + # specifies output target. + # It should respond to <<. + # If it is not specified, $stdout is used. + # + # The second optional argument, encoding, + # specifies output MIME charset (character encoding). + # If it is not specified, HTree::Encoder.internal_charset is used. + # + # HTree::Node#display_xml returns out. + def display_xml(out=$stdout, encoding=HTree::Encoder.internal_charset) + encoder = HTree::Encoder.new(encoding) + self.output(encoder, HTree::DefaultContext) + # don't call finish_with_xmldecl because self already has a xml decl. + out << encoder.finish + out + end + + # HTree::Node#display_html prints the node as HTML. + # + # The first optional argument, out, + # specifies output target. + # It should respond to <<. + # If it is not specified, $stdout is used. + # + # The second optional argument, encoding, + # specifies output MIME charset (character encoding). + # If it is not specified, HTree::Encoder.internal_charset is used. + # + # HTree::Node#display_html returns out. + def display_html(out=$stdout, encoding=HTree::Encoder.internal_charset) + encoder = HTree::Encoder.new(encoding) + encoder.html_output = true + self.output(encoder, HTree::HTMLContext) + out << encoder.finish + out + end + + end +end diff --git a/vendor/htree/htree/doc.rb b/vendor/htree/htree/doc.rb new file mode 100644 index 0000000..def6e38 --- /dev/null +++ b/vendor/htree/htree/doc.rb @@ -0,0 +1,149 @@ +require 'htree/modules' +require 'htree/container' + +module HTree + class Doc + # :stopdoc: + class << self + alias new! new + end + # :startdoc: + + # The arguments should be a sequence of follows. + # [String object] specified string is converted to HTree::Text. + # [HTree::Node object] used as a child. + # [HTree::Doc object] + # used as children. + # It is expanded except HTree::XMLDecl and HTree::DocType objects. + # [Array of String, HTree::Node and HTree::Doc] used as children. + # + def Doc.new(*args) + children = [] + args.each {|arg| + arg = arg.to_node if HTree::Location === arg + case arg + when Array + arg.each {|a| + a = a.to_node if HTree::Location === a + case a + when HTree::Doc + children.concat(a.children.reject {|c| + HTree::XMLDecl === c || HTree::DocType === c + }) + when HTree::Node + children << a + when String + children << Text.new(a) + else + raise TypeError, "unexpected argument: #{arg.inspect}" + end + } + when HTree::Doc + children.concat(arg.children.reject {|c| + HTree::XMLDecl === c || HTree::DocType === c + }) + when HTree::Node + children << arg + when String + children << Text.new(arg) + else + raise TypeError, "unexpected argument: #{arg.inspect}" + end + } + new!(children) + end + + def initialize(children=[]) # :notnew: + @children = children.dup.freeze + unless @children.all? {|c| c.kind_of?(HTree::Node) and !c.kind_of?(HTree::Doc) } + unacceptable = @children.reject {|c| c.kind_of?(HTree::Node) and !c.kind_of?(HTree::Doc) } + unacceptable = unacceptable.map {|uc| uc.inspect }.join(', ') + raise TypeError, "Unacceptable document child: #{unacceptable}" + end + end + + def get_subnode_internal(index) # :nodoc: + unless Integer === index + raise TypeError, "invalid index: #{index.inspect}" + end + if index < 0 || @children.length <= index + nil + else + @children[index] + end + end + + # doc.subst_subnode(pairs) -> doc + # + # The argument _pairs_ should be a hash or an assocs. + # Its key should be an integer which means an index for children. + # + # Its value should be one of follows. + # [HTree::Node object] specified object is used as is. + # [String object] specified string is converted to HTree::Text + # [Array of above] specified HTree::Node and String is used in that order. + # [nil] delete corresponding node. + # + # d = HTree('') + # p d.subst_subnode({0=>HTree(''), 2=>HTree('')}) + # p d.subst_subnode([[0,HTree('')], [2,HTree('')]]) + # # => + # #} {emptyelem } {emptyelem }> + # #} {emptyelem } {emptyelem }> + # + def subst_subnode(pairs) + hash = {} + pairs.each {|index, value| + unless Integer === index + raise TypeError, "invalid index: #{index.inspect}" + end + value = value.to_node if HTree::Location === value + case value + when Node + value = [value] + when String + value = [value] + when Array + value = value.dup + when nil + value = [] + else + raise TypeError, "invalid value: #{value.inspect}" + end + value.map! {|v| + v = v.to_node if HTree::Location === v + case v + when Node + v + when String + Text.new(v) + else + raise TypeError, "invalid value: #{v.inspect}" + end + } + if !hash.include?(index) + hash[index] = [] + end + hash[index].concat value + } + + children_left = [] + children = @children.dup + children_right = [] + + hash.keys.sort.each {|index| + value = hash[index] + if index < 0 + children_left << value + elsif children.length <= index + children_right << value + else + children[index] = value + end + } + + children = [children_left, children, children_right].flatten.compact + Doc.new(children) + end + end +end diff --git a/vendor/htree/htree/elem.rb b/vendor/htree/htree/elem.rb new file mode 100644 index 0000000..61afa2f --- /dev/null +++ b/vendor/htree/htree/elem.rb @@ -0,0 +1,262 @@ +require 'htree/modules' +require 'htree/tag' +require 'htree/context' +require 'htree/container' + +module HTree + class Elem + # :stopdoc: + class << self + alias new! new + end + # :startdoc: + + # The first argument _name_ should be an instance of String or HTree::Name. + # + # The rest of arguments should be a sequence of follows. + # [Hash object] used as attributes. + # [String object] specified string is converted to HTree::Text. + # [HTree::Node object] used as a child. + # [HTree::Doc object] + # used as children. + # It is expanded except HTree::XMLDecl and HTree::DocType objects. + # [Array of String, HTree::Node, HTree::Doc] used as children. + # [HTree::Context object] + # used as as context which represents XML namespaces. + # This should apper once at most. + # + # HTree::Location object is accepted just as HTree::Node. + # + # If the rest arguments consists only + # Hash and HTree::Context, empty element is created. + # + # p HTree::Elem.new("e").empty_element? # => true + # p HTree::Elem.new("e", []).empty_element? # => false + def Elem.new(name, *args) + attrs = [] + children = [] + context = nil + args.each {|arg| + arg = arg.to_node if HTree::Location === arg + case arg + when Context + raise ArgumentError, "multiple context" if context + context = arg + when Hash + arg.each {|k, v| attrs << [k, v] } + when Array + arg.each {|a| + a = a.to_node if HTree::Location === a + case a + when HTree::Doc + children.concat(a.children.reject {|c| + HTree::XMLDecl === c || HTree::DocType === c + }) + when HTree::Node + children << a + when String + children << Text.new(a) + else + raise TypeError, "unexpected argument: #{arg.inspect}" + end + } + when HTree::Doc + children.concat(arg.children.reject {|c| + HTree::XMLDecl === c || HTree::DocType === c + }) + when HTree::Node + children << arg + when String + children << Text.new(arg) + + else + raise TypeError, "unexpected argument: #{arg.inspect}" + end + } + context ||= DefaultContext + if children.empty? && args.all? {|arg| Hash === arg || Context === arg } + children = nil + end + new!(STag.new(name, attrs, context), children) + end + + def initialize(stag, children=nil, etag=nil) # :notnew: + unless stag.class == STag + raise TypeError, "HTree::STag expected: #{stag.inspect}" + end + unless !children || children.all? {|c| c.kind_of?(HTree::Node) and !c.kind_of?(HTree::Doc) } + unacceptable = children.reject {|c| c.kind_of?(HTree::Node) and !c.kind_of?(HTree::Doc) } + unacceptable = unacceptable.map {|uc| uc.inspect }.join(', ') + raise TypeError, "Unacceptable element child: #{unacceptable}" + end + unless !etag || etag.class == ETag + raise TypeError, "HTree::ETag expected: #{etag.inspect}" + end + @stag = stag + @children = (children ? children.dup : []).freeze + @empty = children == nil && etag == nil + @etag = etag + end + + def context; @stag.context end + + # +element_name+ returns the name of the element name as a Name object. + def element_name() @stag.element_name end + + def empty_element? + @empty + end + + def each_attribute(&block) # :yields: attr_name, attr_text + @stag.each_attribute(&block) + end + + def get_subnode_internal(index) # :nodoc: + case index + when String + name = Name.parse_attribute_name(index, DefaultContext) + update_attribute_hash[name.universal_name] + when Name + update_attribute_hash[index.universal_name] + when Integer + if index < 0 || @children.length <= index + nil + else + @children[index] + end + else + raise TypeError, "invalid index: #{index.inspect}" + end + end + + # call-seq: + # elem.subst_subnode(pairs) -> elem + # + # The argument _pairs_ should be a hash or an assocs. + # + # The key of pairs should be one of following. + # [HTree::Name or String object] attribute name. + # [Integer object] child index. + # + # The value of pairs should be one of follows. + # [HTree::Node object] specified object is used as is. + # [String object] specified string is converted to HTree::Text + # [Array of above] specified HTree::Node and String is used in that order. + # [nil] delete corresponding node. + # + # e = HTree('').root + # p e.subst_subnode({0=>HTree(''), 2=>HTree('')}) + # p e.subst_subnode([[0, HTree('')], [2,HTree('')]]) + # # => + # {elem {emptyelem } {emptyelem } {emptyelem }} + # {elem {emptyelem } {emptyelem } {emptyelem }} + # + def subst_subnode(pairs) + hash = {} + pairs.each {|index, value| + case index + when Name, Integer + when String + index = Name.parse_attribute_name(index, DefaultContext) + else + raise TypeError, "invalid index: #{index.inspect}" + end + value = value.to_node if HTree::Location === value + case value + when Node + value = [value] + when String + value = [value] + when Array + value = value.dup + when nil + value = [] + else + raise TypeError, "invalid value: #{value.inspect}" + end + value.map! {|v| + v = v.to_node if HTree::Location === v + case v + when Node + v + when String + Text.new(v) + else + raise TypeError, "invalid value: #{v.inspect}" + end + } + if !hash.include?(index) + hash[index] = [] + end + hash[index].concat value + } + + attrs = [] + @stag.attributes.each {|k, v| + if hash.include? k + v = hash[k] + if !v.empty? + attrs << {k=>Text.concat(*v)} + end + hash.delete k + else + attrs << {k=>v} + end + } + hash.keys.each {|k| + if Name === k + v = hash[k] + if !v.empty? + attrs << {k=>Text.concat(*v)} + end + hash.delete k + end + } + + children_left = [] + children = @children.dup + children_right = [] + + hash.keys.sort.each {|index| + value = hash[index] + if index < 0 + children_left << value + elsif children.length <= index + children_right << value + else + children[index] = value + end + } + + children = [children_left, children, children_right].flatten + + if children.empty? && @empty + Elem.new( + @stag.element_name, + @stag.context, + *attrs) + else + Elem.new( + @stag.element_name, + @stag.context, + children, + *attrs) + end + end + end + + module Elem::Trav + private + def update_attribute_hash + if defined?(@attribute_hash) + @attribute_hash + else + h = {} + each_attribute {|name, text| + h[name.universal_name] = text + } + @attribute_hash = h + end + end + end +end diff --git a/vendor/htree/htree/encoder.rb b/vendor/htree/htree/encoder.rb new file mode 100644 index 0000000..7840260 --- /dev/null +++ b/vendor/htree/htree/encoder.rb @@ -0,0 +1,212 @@ +require 'iconv' + +module HTree + class Encoder + # HTree::Encoder.internal_charset returns the MIME charset corresponding to $KCODE. + # + # - 'ISO-8859-1' when $KCODE=='NONE' + # - 'UTF-8' when $KCODE=='UTF8' + # - 'EUC-JP' when $KCODE=='EUC' + # - 'Shift_JIS' when $KCODE=='SJIS' + # + # This mapping ignores EUC-KR and various single byte charset other than ISO-8859-1 at least. + # This should be fixed when Ruby is m17nized. + def Encoder.internal_charset + KcodeCharset[$KCODE] + end + + def initialize(output_encoding, internal_encoding=HTree::Encoder.internal_charset) + @buf = '' + @internal_encoding = internal_encoding + @output_encoding = output_encoding + @ic = Iconv.new(output_encoding, @internal_encoding) + @charpat = FirstCharPattern[internal_encoding] + + @subcharset_list = SubCharset[output_encoding] || [] + @subcharset_ic = {} + @subcharset_list.each {|subcharset| + @subcharset_ic[subcharset] = Iconv.new(subcharset, @internal_encoding) + } + @html_output = false + end + + # :stopdoc: + def html_output? + @html_output + end + + def html_output=(flag) + @html_output = flag + end + + def output_cdata_content_do(out, pre, body, post) + if @html_output + pre.call + body.call + post.call(out) + else + body.call + end + return out + end + + def output_slash_if_xml + if !@html_output + output_string('/') + end + end + + def output_cdata_content(content, context) + if @html_output + # xxx: should raise an error for non-text node? + texts = content.grep(HTree::Text) + text = HTree::Text.concat(*texts) + text.output_cdata(self) + else + content.each {|n| n.output(self, context) } + end + end + + def output_cdata_for_html(*args) + str = args.join('') + if %r{ e + output_string string[0, string.length - e.failed.length], e.success + unless @charpat =~ e.failed + # xxx: should be configulable? + #raise ArgumentError, "cannot extract first character: #{e.failed.dump}" + string = e.failed[1, e.failed.length-1] + output_string '?' + retry + end + char = $& + rest = $' + begin + ucode = Iconv.conv("UTF-8", @internal_encoding, char).unpack("U")[0] + char = "&##{ucode};" + rescue Iconv::IllegalSequence, Iconv::InvalidCharacter + # xxx: should be configulable? + char = '?' + end + output_string char + string = rest + retry + end + end + + ChRef = { + '&' => '&', + '<' => '<', + '>' => '>', + '"' => '"', + } + + def output_dynamic_text(string) + if string.respond_to? :rcdata + output_text(string.rcdata.gsub(/[<>]/) { ChRef[$&] }) + else + output_text(string.to_s.gsub(/[&<>]/) { ChRef[$&] }) + end + end + + def output_dynamic_attvalue(string) + if string.respond_to? :rcdata + output_text(string.rcdata.gsub(/[<>"]/) { ChRef[$&] }) + else + output_text(string.to_s.gsub(/[&<>"]/) { ChRef[$&] }) + end + end + + # :startdoc: + + def finish + external_str = @ic.close + @buf << external_str + @subcharset_ic.reject! {|subcharset, ic| + begin + ic.close != external_str + rescue Iconv::Failure + true + end + } + @buf + end + + def finish_with_xmldecl + content = finish + xmldecl = Iconv.conv(@output_encoding, 'US-ASCII', + "") + xmldecl + content + end + + def minimal_charset + @subcharset_list.each {|subcharset| + if @subcharset_ic.include? subcharset + return subcharset + end + } + @output_encoding + end + + # :stopdoc: + + KcodeCharset = { + 'EUC' => 'EUC-JP', + 'SJIS' => 'Shift_JIS', + 'UTF8' => 'UTF-8', + 'NONE' => 'ISO-8859-1', + } + + FirstCharPattern = { + 'EUC-JP' => /\A(?: + [\x00-\x7f] + |[\xa1-\xfe][\xa1-\xfe] + |\x8e[\xa1-\xfe] + |\x8f[\xa1-\xfe][\xa1-\xfe])/nx, + 'Shift_JIS' => /\A(?: + [\x00-\x7f] + |[\x81-\x9f][\x40-\x7e\x80-\xfc] + |[\xa1-\xdf] + |[\xe0-\xfc][\x40-\x7e\x80-\xfc])/nx, + 'UTF-8' => /\A(?: + [\x00-\x7f] + |[\xc0-\xdf][\x80-\xbf] + |[\xe0-\xef][\x80-\xbf][\x80-\xbf] + |[\xf0-\xf7][\x80-\xbf][\x80-\xbf][\x80-\xbf] + |[\xf8-\xfb][\x80-\xbf][\x80-\xbf][\x80-\xbf][\x80-\xbf] + |[\xfc-\xfd][\x80-\xbf][\x80-\xbf][\x80-\xbf][\x80-\xbf][\x80-\xbf])/nx, + 'ISO-8859-1' => /\A[\x00-\xff]/n + } + + SubCharset = { + 'ISO-2022-JP-2' => ['US-ASCII', 'ISO-2022-JP'], + 'ISO-2022-JP-3' => ['US-ASCII', 'ISO-2022-JP'], + 'UTF-16BE' => [], + 'UTF-16LE' => [], + 'UTF-16' => [], + } + SubCharset.default = ['US-ASCII'] + + # :startdoc: + end +end diff --git a/vendor/htree/htree/equality.rb b/vendor/htree/htree/equality.rb new file mode 100644 index 0000000..4595cca --- /dev/null +++ b/vendor/htree/htree/equality.rb @@ -0,0 +1,219 @@ +require 'htree/doc' +require 'htree/elem' +require 'htree/leaf' +require 'htree/tag' +require 'htree/raw_string' +require 'htree/context' + +module HTree + # compare tree structures. + def ==(other) + check_equality(self, other, :usual_equal_object) + end + alias eql? == + + # hash value for the tree structure. + def hash + return @hash_code if defined? @hash_code + @hash_code = usual_equal_object.hash + end + + # :stopdoc: + + def usual_equal_object + return @usual_equal_object if defined? @usual_equal_object + @usual_equal_object = make_usual_equal_object + end + + def make_usual_equal_object + raise NotImplementedError + end + + def exact_equal_object + return @exact_equal_object if defined? @exact_equal_object + @exact_equal_object = make_exact_equal_object + end + + def make_exact_equal_object + raise NotImplementedError + end + + def exact_equal?(other) + check_equality(self, other, :exact_equal_object) + end + + def check_equality(obj1, obj2, equal_object_method) + return false unless obj1.class == obj2.class + if obj1.class == Array + return false unless obj1.length == obj2.length + obj1.each_with_index {|c1, i| + return false unless c1.class == obj2[i].class + } + obj1.each_with_index {|c1, i| + return false unless check_equality(c1, obj2[i], equal_object_method) + } + true + elsif obj1.respond_to? equal_object_method + o1 = obj1.send(equal_object_method) + o2 = obj2.send(equal_object_method) + check_equality(o1, o2, equal_object_method) + else + obj1 == obj2 + end + end + + class Doc + alias exact_equal_object children + alias usual_equal_object children + end + + class Elem + def make_exact_equal_object + [@stag, @children, @empty, @etag] + end + + def make_usual_equal_object + [@stag, @children] + end + end + + class Name + def make_exact_equal_object + [@namespace_prefix, @namespace_uri, @local_name] + end + + def make_usual_equal_object + xmlns? ? @local_name : [@namespace_uri, @local_name] + end + end + + module Util + module_function + def cmp_with_nil(a, b) + if a == nil + if b == nil + 0 + else + -1 + end + else + if b == nil + 1 + else + a <=> b + end + end + end + end + + class Context + def make_exact_equal_object + @namespaces.keys.sort {|prefix1, prefix2| + Util.cmp_with_nil(prefix1, prefix2) + }.map {|prefix| [prefix, @namespaces[prefix]] } + end + + # make_usual_equal_object is not used through STag#make_usual_equal_object + # NotImplementedError is suitable? + alias make_usual_equal_object make_exact_equal_object + end + + class STag + def make_exact_equal_object + [@raw_string, + @name, + @attributes.sort {|(n1,t1), (n2, t2)| + Util.cmp_with_nil(n1.namespace_prefix, n2.namespace_prefix).nonzero? || + Util.cmp_with_nil(n1.namespace_uri, n2.namespace_uri).nonzero? || + Util.cmp_with_nil(n1.local_name, n2.local_name) + }, + @inherited_context + ] + end + + def make_usual_equal_object + [@name, + @attributes.find_all {|n,t| !n.xmlns? }.sort {|(n1,t1), (n2, t2)| + Util.cmp_with_nil(n1.namespace_prefix, n2.namespace_prefix).nonzero? || + Util.cmp_with_nil(n1.namespace_uri, n2.namespace_uri).nonzero? || + Util.cmp_with_nil(n1.local_name, n2.local_name) + } + ] + end + + end + + class ETag + def make_exact_equal_object + [@raw_string, @qualified_name] + end + + alias usual_equal_object qualified_name + end + + class Text + def make_exact_equal_object + [@raw_string, @rcdata] + end + + def make_usual_equal_object + @normalized_rcdata + end + end + + class XMLDecl + def make_exact_equal_object + [@raw_string, @version, @encoding, @standalone] + end + + def make_usual_equal_object + [@version, @encoding, @standalone] + end + end + + class DocType + def make_exact_equal_object + [@raw_string, @root_element_name, @system_identifier, @public_identifier] + end + + def make_usual_equal_object + [@root_element_name, @system_identifier, @public_identifier] + end + end + + class ProcIns + def make_exact_equal_object + [@raw_string, @target, @content] + end + + def make_usual_equal_object + [@target, @content] + end + end + + class Comment + def make_exact_equal_object + [@raw_string, @content] + end + + alias usual_equal_object content + end + + class BogusETag + def make_exact_equal_object + [@etag] + end + + alias usual_equal_object make_exact_equal_object + end + + class Location + def make_exact_equal_object + [@parent, @index, @node] + end + + alias usual_equal_object make_exact_equal_object + end + + # :startdoc: +end diff --git a/vendor/htree/htree/extract_text.rb b/vendor/htree/htree/extract_text.rb new file mode 100644 index 0000000..711f9f4 --- /dev/null +++ b/vendor/htree/htree/extract_text.rb @@ -0,0 +1,37 @@ +require 'htree/text' +require 'htree/doc' +require 'htree/elem' + +module HTree + module Node + def extract_text + raise NotImplementedError + end + end + + class Location + def extract_text + to_node.extract_text + end + end + + # :stopdoc: + module Container + def extract_text + Text.concat(*@children.map {|n| n.extract_text }) + end + end + + module Leaf + def extract_text + Text.new('') + end + end + + class Text + def extract_text + self + end + end + # :startdoc: +end diff --git a/vendor/htree/htree/fstr.rb b/vendor/htree/htree/fstr.rb new file mode 100644 index 0000000..a731c3d --- /dev/null +++ b/vendor/htree/htree/fstr.rb @@ -0,0 +1,32 @@ +require 'htree/modules' + +module HTree + # :stopdoc: + def HTree.with_frozen_string_hash + if Thread.current[:htree_frozen_string_hash] + yield + else + begin + Thread.current[:htree_frozen_string_hash] = {} + yield + ensure + Thread.current[:htree_frozen_string_hash] = nil + end + end + end + + def HTree.frozen_string(str) + if h = Thread.current[:htree_frozen_string_hash] + if s = h[str] + s + else + str = str.dup.freeze unless str.frozen? + h[str] = str + end + else + str = str.dup.freeze unless str.frozen? + str + end + end + # :startdoc: +end diff --git a/vendor/htree/htree/gencode.rb b/vendor/htree/htree/gencode.rb new file mode 100644 index 0000000..dde5df3 --- /dev/null +++ b/vendor/htree/htree/gencode.rb @@ -0,0 +1,193 @@ +require 'htree/encoder' +require 'htree/output' + +# :stopdoc: + +module HTree + module Node + def generate_xml_output_code(outvar='out', contextvar='top_context') + namespaces = HTree::Context::DefaultNamespaces.dup + namespaces.default = nil + context = Context.new(namespaces) + gen = HTree::GenCode.new(outvar, contextvar) + output(gen, context) + gen.finish + end + end + + class GenCode + def initialize(outvar, contextvar, internal_encoding=Encoder.internal_charset) + @outvar = outvar + @contextvar = contextvar + @state = :none + @buffer = '' + @internal_encoding = internal_encoding + @code = '' + @html_output = nil + end + attr_reader :outvar, :contextvar + + def html_output? + @html_output + end + + def html_output=(flag) + @html_output = flag + end + + class CDATABuffer + def initialize + @buf = '' + end + + def html_output? + true + end + + def not_valid_for_html_cdata(*args) + raise ArgumentError, "CDATA content only accept texts." + end + alias output_slash_if_xml not_valid_for_html_cdata + alias output_cdata_content not_valid_for_html_cdata + alias output_dynamic_attvalue not_valid_for_html_cdata + + def output_string(string) + @buf << string + end + + def output_text(string) + @buf << string + end + + ChRef = { + '&' => '&', + '<' => '<', + '>' => '>', + '"' => '"', + } + + def output_dynamic_text(string) + if string.respond_to? :rcdata + @buf << string.rcdata.gsub(/[<>]/) { ChRef[$&] } + else + @buf << string.to_s.gsub(/[&<>]/) { ChRef[$&] } + end + end + + def result + if %r{[<>]} =~ @buf + raise ArgumentError, "cdata contains non-text : #{@buf.inspect}" + end + str = HTree::Text.parse_pcdata(@buf).to_s + if %r{ '&', + '>' => '>', + '<' => '<', + '"' => '"', + } + def output_xmlns(namespaces) + unless namespaces.empty? + flush_buffer + namespaces.each {|k, v| + if k + ks = k.dump + aname = "xmlns:#{k}" + else + ks = "nil" + aname = "xmlns" + end + @code << "if #{@contextvar}.namespace_uri(#{ks}) != #{v.dump}\n" + output_string " #{aname}=\"" + output_text v.gsub(/[&<>"]/) {|s| ChRef[s] } + output_string '"' + flush_buffer + @code << "end\n" + } + end + end + + def flush_buffer + return if @buffer.empty? + case @state + when :string + @code << "#{@outvar}.output_string #{@buffer.dump}\n" + @buffer = '' + when :text + @code << "#{@outvar}.output_text #{@buffer.dump}\n" + @buffer = '' + end + end + + def finish + flush_buffer + @code + end + end +end + +# :startdoc: diff --git a/vendor/htree/htree/htmlinfo.rb b/vendor/htree/htree/htmlinfo.rb new file mode 100644 index 0000000..d4206c2 --- /dev/null +++ b/vendor/htree/htree/htmlinfo.rb @@ -0,0 +1,672 @@ +module HTree +# The code below is auto-generated. Don't edit manually. + # :stopdoc: + NamedCharacters = +{"AElig"=>198, "Aacute"=>193, "Acirc"=>194, "Agrave"=>192, "Alpha"=>913, + "Aring"=>197, "Atilde"=>195, "Auml"=>196, "Beta"=>914, "Ccedil"=>199, + "Chi"=>935, "Dagger"=>8225, "Delta"=>916, "ETH"=>208, "Eacute"=>201, + "Ecirc"=>202, "Egrave"=>200, "Epsilon"=>917, "Eta"=>919, "Euml"=>203, + "Gamma"=>915, "Iacute"=>205, "Icirc"=>206, "Igrave"=>204, "Iota"=>921, + "Iuml"=>207, "Kappa"=>922, "Lambda"=>923, "Mu"=>924, "Ntilde"=>209, "Nu"=>925, + "OElig"=>338, "Oacute"=>211, "Ocirc"=>212, "Ograve"=>210, "Omega"=>937, + "Omicron"=>927, "Oslash"=>216, "Otilde"=>213, "Ouml"=>214, "Phi"=>934, + "Pi"=>928, "Prime"=>8243, "Psi"=>936, "Rho"=>929, "Scaron"=>352, "Sigma"=>931, + "THORN"=>222, "Tau"=>932, "Theta"=>920, "Uacute"=>218, "Ucirc"=>219, + "Ugrave"=>217, "Upsilon"=>933, "Uuml"=>220, "Xi"=>926, "Yacute"=>221, + "Yuml"=>376, "Zeta"=>918, "aacute"=>225, "acirc"=>226, "acute"=>180, + "aelig"=>230, "agrave"=>224, "alefsym"=>8501, "alpha"=>945, "amp"=>38, + "and"=>8743, "ang"=>8736, "apos"=>39, "aring"=>229, "asymp"=>8776, + "atilde"=>227, "auml"=>228, "bdquo"=>8222, "beta"=>946, "brvbar"=>166, + "bull"=>8226, "cap"=>8745, "ccedil"=>231, "cedil"=>184, "cent"=>162, + "chi"=>967, "circ"=>710, "clubs"=>9827, "cong"=>8773, "copy"=>169, + "crarr"=>8629, "cup"=>8746, "curren"=>164, "dArr"=>8659, "dagger"=>8224, + "darr"=>8595, "deg"=>176, "delta"=>948, "diams"=>9830, "divide"=>247, + "eacute"=>233, "ecirc"=>234, "egrave"=>232, "empty"=>8709, "emsp"=>8195, + "ensp"=>8194, "epsilon"=>949, "equiv"=>8801, "eta"=>951, "eth"=>240, + "euml"=>235, "euro"=>8364, "exist"=>8707, "fnof"=>402, "forall"=>8704, + "frac12"=>189, "frac14"=>188, "frac34"=>190, "frasl"=>8260, "gamma"=>947, + "ge"=>8805, "gt"=>62, "hArr"=>8660, "harr"=>8596, "hearts"=>9829, + "hellip"=>8230, "iacute"=>237, "icirc"=>238, "iexcl"=>161, "igrave"=>236, + "image"=>8465, "infin"=>8734, "int"=>8747, "iota"=>953, "iquest"=>191, + "isin"=>8712, "iuml"=>239, "kappa"=>954, "lArr"=>8656, "lambda"=>955, + "lang"=>9001, "laquo"=>171, "larr"=>8592, "lceil"=>8968, "ldquo"=>8220, + "le"=>8804, "lfloor"=>8970, "lowast"=>8727, "loz"=>9674, "lrm"=>8206, + "lsaquo"=>8249, "lsquo"=>8216, "lt"=>60, "macr"=>175, "mdash"=>8212, + "micro"=>181, "middot"=>183, "minus"=>8722, "mu"=>956, "nabla"=>8711, + "nbsp"=>160, "ndash"=>8211, "ne"=>8800, "ni"=>8715, "not"=>172, "notin"=>8713, + "nsub"=>8836, "ntilde"=>241, "nu"=>957, "oacute"=>243, "ocirc"=>244, + "oelig"=>339, "ograve"=>242, "oline"=>8254, "omega"=>969, "omicron"=>959, + "oplus"=>8853, "or"=>8744, "ordf"=>170, "ordm"=>186, "oslash"=>248, + "otilde"=>245, "otimes"=>8855, "ouml"=>246, "para"=>182, "part"=>8706, + "permil"=>8240, "perp"=>8869, "phi"=>966, "pi"=>960, "piv"=>982, + "plusmn"=>177, "pound"=>163, "prime"=>8242, "prod"=>8719, "prop"=>8733, + "psi"=>968, "quot"=>34, "rArr"=>8658, "radic"=>8730, "rang"=>9002, + "raquo"=>187, "rarr"=>8594, "rceil"=>8969, "rdquo"=>8221, "real"=>8476, + "reg"=>174, "rfloor"=>8971, "rho"=>961, "rlm"=>8207, "rsaquo"=>8250, + "rsquo"=>8217, "sbquo"=>8218, "scaron"=>353, "sdot"=>8901, "sect"=>167, + "shy"=>173, "sigma"=>963, "sigmaf"=>962, "sim"=>8764, "spades"=>9824, + "sub"=>8834, "sube"=>8838, "sum"=>8721, "sup"=>8835, "sup1"=>185, "sup2"=>178, + "sup3"=>179, "supe"=>8839, "szlig"=>223, "tau"=>964, "there4"=>8756, + "theta"=>952, "thetasym"=>977, "thinsp"=>8201, "thorn"=>254, "tilde"=>732, + "times"=>215, "trade"=>8482, "uArr"=>8657, "uacute"=>250, "uarr"=>8593, + "ucirc"=>251, "ugrave"=>249, "uml"=>168, "upsih"=>978, "upsilon"=>965, + "uuml"=>252, "weierp"=>8472, "xi"=>958, "yacute"=>253, "yen"=>165, + "yuml"=>255, "zeta"=>950, "zwj"=>8205, "zwnj"=>8204} + + + NamedCharactersPattern = /\A(?-mix:AElig|Aacute|Acirc|Agrave|Alpha|Aring|Atilde|Auml|Beta|Ccedil|Chi|Dagger|Delta|ETH|Eacute|Ecirc|Egrave|Epsilon|Eta|Euml|Gamma|Iacute|Icirc|Igrave|Iota|Iuml|Kappa|Lambda|Mu|Ntilde|Nu|OElig|Oacute|Ocirc|Ograve|Omega|Omicron|Oslash|Otilde|Ouml|Phi|Pi|Prime|Psi|Rho|Scaron|Sigma|THORN|Tau|Theta|Uacute|Ucirc|Ugrave|Upsilon|Uuml|Xi|Yacute|Yuml|Zeta|aacute|acirc|acute|aelig|agrave|alefsym|alpha|amp|and|ang|apos|aring|asymp|atilde|auml|bdquo|beta|brvbar|bull|cap|ccedil|cedil|cent|chi|circ|clubs|cong|copy|crarr|cup|curren|dArr|dagger|darr|deg|delta|diams|divide|eacute|ecirc|egrave|empty|emsp|ensp|epsilon|equiv|eta|eth|euml|euro|exist|fnof|forall|frac12|frac14|frac34|frasl|gamma|ge|gt|hArr|harr|hearts|hellip|iacute|icirc|iexcl|igrave|image|infin|int|iota|iquest|isin|iuml|kappa|lArr|lambda|lang|laquo|larr|lceil|ldquo|le|lfloor|lowast|loz|lrm|lsaquo|lsquo|lt|macr|mdash|micro|middot|minus|mu|nabla|nbsp|ndash|ne|ni|not|notin|nsub|ntilde|nu|oacute|ocirc|oelig|ograve|oline|omega|omicron|oplus|or|ordf|ordm|oslash|otilde|otimes|ouml|para|part|permil|perp|phi|pi|piv|plusmn|pound|prime|prod|prop|psi|quot|rArr|radic|rang|raquo|rarr|rceil|rdquo|real|reg|rfloor|rho|rlm|rsaquo|rsquo|sbquo|scaron|sdot|sect|shy|sigma|sigmaf|sim|spades|sub|sube|sum|sup|sup1|sup2|sup3|supe|szlig|tau|there4|theta|thetasym|thinsp|thorn|tilde|times|trade|uArr|uacute|uarr|ucirc|ugrave|uml|upsih|upsilon|uuml|weierp|xi|yacute|yen|yuml|zeta|zwj|zwnj)\z/ + + ElementContent = +{"h6"=> + ["a", "abbr", "acronym", "applet", "b", "basefont", "bdo", "big", "br", + "button", "cite", "code", "dfn", "em", "font", "i", "iframe", "img", + "input", "kbd", "label", "map", "object", "q", "s", "samp", "script", + "select", "small", "span", "strike", "strong", "sub", "sup", "textarea", + "tt", "u", "var"], + "object"=> + ["a", "abbr", "acronym", "address", "applet", "b", "basefont", "bdo", "big", + "blockquote", "br", "button", "center", "cite", "code", "dfn", "dir", "div", + "dl", "em", "fieldset", "font", "form", "h1", "h2", "h3", "h4", "h5", "h6", + "hr", "i", "iframe", "img", "input", "isindex", "kbd", "label", "map", + "menu", "noframes", "noscript", "object", "ol", "p", "param", "pre", "q", + "s", "samp", "script", "select", "small", "span", "strike", "strong", "sub", + "sup", "table", "textarea", "tt", "u", "ul", "var"], + "dl"=>["dd", "dt"], + "p"=> + ["a", "abbr", "acronym", "applet", "b", "basefont", "bdo", "big", "br", + "button", "cite", "code", "dfn", "em", "font", "i", "iframe", "img", + "input", "kbd", "label", "map", "object", "q", "s", "samp", "script", + "select", "small", "span", "strike", "strong", "sub", "sup", "textarea", + "tt", "u", "var"], + "acronym"=> + ["a", "abbr", "acronym", "applet", "b", "basefont", "bdo", "big", "br", + "button", "cite", "code", "dfn", "em", "font", "i", "iframe", "img", + "input", "kbd", "label", "map", "object", "q", "s", "samp", "script", + "select", "small", "span", "strike", "strong", "sub", "sup", "textarea", + "tt", "u", "var"], + "code"=> + ["a", "abbr", "acronym", "applet", "b", "basefont", "bdo", "big", "br", + "button", "cite", "code", "dfn", "em", "font", "i", "iframe", "img", + "input", "kbd", "label", "map", "object", "q", "s", "samp", "script", + "select", "small", "span", "strike", "strong", "sub", "sup", "textarea", + "tt", "u", "var"], + "ul"=>["li"], + "tt"=> + ["a", "abbr", "acronym", "applet", "b", "basefont", "bdo", "big", "br", + "button", "cite", "code", "dfn", "em", "font", "i", "iframe", "img", + "input", "kbd", "label", "map", "object", "q", "s", "samp", "script", + "select", "small", "span", "strike", "strong", "sub", "sup", "textarea", + "tt", "u", "var"], + "label"=> + ["a", "abbr", "acronym", "applet", "b", "basefont", "bdo", "big", "br", + "button", "cite", "code", "dfn", "em", "font", "i", "iframe", "img", + "input", "kbd", "label", "map", "object", "q", "s", "samp", "script", + "select", "small", "span", "strike", "strong", "sub", "sup", "textarea", + "tt", "u", "var"], + "form"=> + ["a", "abbr", "acronym", "address", "applet", "b", "basefont", "bdo", "big", + "blockquote", "br", "button", "center", "cite", "code", "dfn", "dir", "div", + "dl", "em", "fieldset", "font", "form", "h1", "h2", "h3", "h4", "h5", "h6", + "hr", "i", "iframe", "img", "input", "isindex", "kbd", "label", "map", + "menu", "noframes", "noscript", "object", "ol", "p", "pre", "q", "s", + "samp", "script", "select", "small", "span", "strike", "strong", "sub", + "sup", "table", "textarea", "tt", "u", "ul", "var"], + "q"=> + ["a", "abbr", "acronym", "applet", "b", "basefont", "bdo", "big", "br", + "button", "cite", "code", "dfn", "em", "font", "i", "iframe", "img", + "input", "kbd", "label", "map", "object", "q", "s", "samp", "script", + "select", "small", "span", "strike", "strong", "sub", "sup", "textarea", + "tt", "u", "var"], + "thead"=>["tr"], + "area"=>:EMPTY, + "td"=> + ["a", "abbr", "acronym", "address", "applet", "b", "basefont", "bdo", "big", + "blockquote", "br", "button", "center", "cite", "code", "dfn", "dir", "div", + "dl", "em", "fieldset", "font", "form", "h1", "h2", "h3", "h4", "h5", "h6", + "hr", "i", "iframe", "img", "input", "isindex", "kbd", "label", "map", + "menu", "noframes", "noscript", "object", "ol", "p", "pre", "q", "s", + "samp", "script", "select", "small", "span", "strike", "strong", "sub", + "sup", "table", "textarea", "tt", "u", "ul", "var"], + "title"=>[], + "dir"=>["li"], + "s"=> + ["a", "abbr", "acronym", "applet", "b", "basefont", "bdo", "big", "br", + "button", "cite", "code", "dfn", "em", "font", "i", "iframe", "img", + "input", "kbd", "label", "map", "object", "q", "s", "samp", "script", + "select", "small", "span", "strike", "strong", "sub", "sup", "textarea", + "tt", "u", "var"], + "ol"=>["li"], + "hr"=>:EMPTY, + "applet"=> + ["a", "abbr", "acronym", "address", "applet", "b", "basefont", "bdo", "big", + "blockquote", "br", "button", "center", "cite", "code", "dfn", "dir", "div", + "dl", "em", "fieldset", "font", "form", "h1", "h2", "h3", "h4", "h5", "h6", + "hr", "i", "iframe", "img", "input", "isindex", "kbd", "label", "map", + "menu", "noframes", "noscript", "object", "ol", "p", "param", "pre", "q", + "s", "samp", "script", "select", "small", "span", "strike", "strong", "sub", + "sup", "table", "textarea", "tt", "u", "ul", "var"], + "table"=>["caption", "col", "colgroup", "tbody", "tfoot", "thead", "tr"], + "legend"=> + ["a", "abbr", "acronym", "applet", "b", "basefont", "bdo", "big", "br", + "button", "cite", "code", "dfn", "em", "font", "i", "iframe", "img", + "input", "kbd", "label", "map", "object", "q", "s", "samp", "script", + "select", "small", "span", "strike", "strong", "sub", "sup", "textarea", + "tt", "u", "var"], + "cite"=> + ["a", "abbr", "acronym", "applet", "b", "basefont", "bdo", "big", "br", + "button", "cite", "code", "dfn", "em", "font", "i", "iframe", "img", + "input", "kbd", "label", "map", "object", "q", "s", "samp", "script", + "select", "small", "span", "strike", "strong", "sub", "sup", "textarea", + "tt", "u", "var"], + "a"=> + ["a", "abbr", "acronym", "applet", "b", "basefont", "bdo", "big", "br", + "button", "cite", "code", "dfn", "em", "font", "i", "iframe", "img", + "input", "kbd", "label", "map", "object", "q", "s", "samp", "script", + "select", "small", "span", "strike", "strong", "sub", "sup", "textarea", + "tt", "u", "var"], + "html"=> + ["a", "abbr", "acronym", "address", "applet", "b", "base", "basefont", "bdo", + "big", "blockquote", "body", "br", "button", "center", "cite", "code", + "dfn", "dir", "div", "dl", "em", "fieldset", "font", "form", "h1", "h2", + "h3", "h4", "h5", "h6", "head", "hr", "i", "iframe", "img", "input", + "isindex", "kbd", "label", "map", "menu", "noframes", "noscript", "object", + "ol", "p", "pre", "q", "s", "samp", "script", "select", "small", "span", + "strike", "strong", "sub", "sup", "table", "textarea", "title", "tt", "u", + "ul", "var"], + "u"=> + ["a", "abbr", "acronym", "applet", "b", "basefont", "bdo", "big", "br", + "button", "cite", "code", "dfn", "em", "font", "i", "iframe", "img", + "input", "kbd", "label", "map", "object", "q", "s", "samp", "script", + "select", "small", "span", "strike", "strong", "sub", "sup", "textarea", + "tt", "u", "var"], + "blockquote"=> + ["a", "abbr", "acronym", "address", "applet", "b", "basefont", "bdo", "big", + "blockquote", "br", "button", "center", "cite", "code", "dfn", "dir", "div", + "dl", "em", "fieldset", "font", "form", "h1", "h2", "h3", "h4", "h5", "h6", + "hr", "i", "iframe", "img", "input", "isindex", "kbd", "label", "map", + "menu", "noframes", "noscript", "object", "ol", "p", "pre", "q", "s", + "samp", "script", "select", "small", "span", "strike", "strong", "sub", + "sup", "table", "textarea", "tt", "u", "ul", "var"], + "center"=> + ["a", "abbr", "acronym", "address", "applet", "b", "basefont", "bdo", "big", + "blockquote", "br", "button", "center", "cite", "code", "dfn", "dir", "div", + "dl", "em", "fieldset", "font", "form", "h1", "h2", "h3", "h4", "h5", "h6", + "hr", "i", "iframe", "img", "input", "isindex", "kbd", "label", "map", + "menu", "noframes", "noscript", "object", "ol", "p", "pre", "q", "s", + "samp", "script", "select", "small", "span", "strike", "strong", "sub", + "sup", "table", "textarea", "tt", "u", "ul", "var"], + "b"=> + ["a", "abbr", "acronym", "applet", "b", "basefont", "bdo", "big", "br", + "button", "cite", "code", "dfn", "em", "font", "i", "iframe", "img", + "input", "kbd", "label", "map", "object", "q", "s", "samp", "script", + "select", "small", "span", "strike", "strong", "sub", "sup", "textarea", + "tt", "u", "var"], + "base"=>:EMPTY, + "th"=> + ["a", "abbr", "acronym", "address", "applet", "b", "basefont", "bdo", "big", + "blockquote", "br", "button", "center", "cite", "code", "dfn", "dir", "div", + "dl", "em", "fieldset", "font", "form", "h1", "h2", "h3", "h4", "h5", "h6", + "hr", "i", "iframe", "img", "input", "isindex", "kbd", "label", "map", + "menu", "noframes", "noscript", "object", "ol", "p", "pre", "q", "s", + "samp", "script", "select", "small", "span", "strike", "strong", "sub", + "sup", "table", "textarea", "tt", "u", "ul", "var"], + "link"=>:EMPTY, + "var"=> + ["a", "abbr", "acronym", "applet", "b", "basefont", "bdo", "big", "br", + "button", "cite", "code", "dfn", "em", "font", "i", "iframe", "img", + "input", "kbd", "label", "map", "object", "q", "s", "samp", "script", + "select", "small", "span", "strike", "strong", "sub", "sup", "textarea", + "tt", "u", "var"], + "samp"=> + ["a", "abbr", "acronym", "applet", "b", "basefont", "bdo", "big", "br", + "button", "cite", "code", "dfn", "em", "font", "i", "iframe", "img", + "input", "kbd", "label", "map", "object", "q", "s", "samp", "script", + "select", "small", "span", "strike", "strong", "sub", "sup", "textarea", + "tt", "u", "var"], + "div"=> + ["a", "abbr", "acronym", "address", "applet", "b", "basefont", "bdo", "big", + "blockquote", "br", "button", "center", "cite", "code", "dfn", "dir", "div", + "dl", "em", "fieldset", "font", "form", "h1", "h2", "h3", "h4", "h5", "h6", + "hr", "i", "iframe", "img", "input", "isindex", "kbd", "label", "map", + "menu", "noframes", "noscript", "object", "ol", "p", "pre", "q", "s", + "samp", "script", "select", "small", "span", "strike", "strong", "sub", + "sup", "table", "textarea", "tt", "u", "ul", "var"], + "textarea"=>[], + "pre"=> + ["a", "abbr", "acronym", "applet", "b", "basefont", "bdo", "big", "br", + "button", "cite", "code", "dfn", "em", "font", "i", "iframe", "img", + "input", "kbd", "label", "map", "object", "q", "s", "samp", "script", + "select", "small", "span", "strike", "strong", "sub", "sup", "textarea", + "tt", "u", "var"], + "head"=>["base", "isindex", "title"], + "span"=> + ["a", "abbr", "acronym", "applet", "b", "basefont", "bdo", "big", "br", + "button", "cite", "code", "dfn", "em", "font", "i", "iframe", "img", + "input", "kbd", "label", "map", "object", "q", "s", "samp", "script", + "select", "small", "span", "strike", "strong", "sub", "sup", "textarea", + "tt", "u", "var"], + "br"=>:EMPTY, + "script"=>:CDATA, + "noframes"=> + ["a", "abbr", "acronym", "address", "applet", "b", "basefont", "bdo", "big", + "blockquote", "br", "button", "center", "cite", "code", "dfn", "dir", "div", + "dl", "em", "fieldset", "font", "form", "h1", "h2", "h3", "h4", "h5", "h6", + "hr", "i", "iframe", "img", "input", "isindex", "kbd", "label", "map", + "menu", "noframes", "noscript", "object", "ol", "p", "pre", "q", "s", + "samp", "script", "select", "small", "span", "strike", "strong", "sub", + "sup", "table", "textarea", "tt", "u", "ul", "var"], + "style"=>:CDATA, + "meta"=>:EMPTY, + "dt"=> + ["a", "abbr", "acronym", "applet", "b", "basefont", "bdo", "big", "br", + "button", "cite", "code", "dfn", "em", "font", "i", "iframe", "img", + "input", "kbd", "label", "map", "object", "q", "s", "samp", "script", + "select", "small", "span", "strike", "strong", "sub", "sup", "textarea", + "tt", "u", "var"], + "option"=>[], + "kbd"=> + ["a", "abbr", "acronym", "applet", "b", "basefont", "bdo", "big", "br", + "button", "cite", "code", "dfn", "em", "font", "i", "iframe", "img", + "input", "kbd", "label", "map", "object", "q", "s", "samp", "script", + "select", "small", "span", "strike", "strong", "sub", "sup", "textarea", + "tt", "u", "var"], + "big"=> + ["a", "abbr", "acronym", "applet", "b", "basefont", "bdo", "big", "br", + "button", "cite", "code", "dfn", "em", "font", "i", "iframe", "img", + "input", "kbd", "label", "map", "object", "q", "s", "samp", "script", + "select", "small", "span", "strike", "strong", "sub", "sup", "textarea", + "tt", "u", "var"], + "tfoot"=>["tr"], + "sup"=> + ["a", "abbr", "acronym", "applet", "b", "basefont", "bdo", "big", "br", + "button", "cite", "code", "dfn", "em", "font", "i", "iframe", "img", + "input", "kbd", "label", "map", "object", "q", "s", "samp", "script", + "select", "small", "span", "strike", "strong", "sub", "sup", "textarea", + "tt", "u", "var"], + "bdo"=> + ["a", "abbr", "acronym", "applet", "b", "basefont", "bdo", "big", "br", + "button", "cite", "code", "dfn", "em", "font", "i", "iframe", "img", + "input", "kbd", "label", "map", "object", "q", "s", "samp", "script", + "select", "small", "span", "strike", "strong", "sub", "sup", "textarea", + "tt", "u", "var"], + "isindex"=>:EMPTY, + "dfn"=> + ["a", "abbr", "acronym", "applet", "b", "basefont", "bdo", "big", "br", + "button", "cite", "code", "dfn", "em", "font", "i", "iframe", "img", + "input", "kbd", "label", "map", "object", "q", "s", "samp", "script", + "select", "small", "span", "strike", "strong", "sub", "sup", "textarea", + "tt", "u", "var"], + "fieldset"=> + ["a", "abbr", "acronym", "address", "applet", "b", "basefont", "bdo", "big", + "blockquote", "br", "button", "center", "cite", "code", "dfn", "dir", "div", + "dl", "em", "fieldset", "font", "form", "h1", "h2", "h3", "h4", "h5", "h6", + "hr", "i", "iframe", "img", "input", "isindex", "kbd", "label", "legend", + "map", "menu", "noframes", "noscript", "object", "ol", "p", "pre", "q", "s", + "samp", "script", "select", "small", "span", "strike", "strong", "sub", + "sup", "table", "textarea", "tt", "u", "ul", "var"], + "em"=> + ["a", "abbr", "acronym", "applet", "b", "basefont", "bdo", "big", "br", + "button", "cite", "code", "dfn", "em", "font", "i", "iframe", "img", + "input", "kbd", "label", "map", "object", "q", "s", "samp", "script", + "select", "small", "span", "strike", "strong", "sub", "sup", "textarea", + "tt", "u", "var"], + "font"=> + ["a", "abbr", "acronym", "applet", "b", "basefont", "bdo", "big", "br", + "button", "cite", "code", "dfn", "em", "font", "i", "iframe", "img", + "input", "kbd", "label", "map", "object", "q", "s", "samp", "script", + "select", "small", "span", "strike", "strong", "sub", "sup", "textarea", + "tt", "u", "var"], + "tbody"=>["tr"], + "noscript"=> + ["a", "abbr", "acronym", "address", "applet", "b", "basefont", "bdo", "big", + "blockquote", "br", "button", "center", "cite", "code", "dfn", "dir", "div", + "dl", "em", "fieldset", "font", "form", "h1", "h2", "h3", "h4", "h5", "h6", + "hr", "i", "iframe", "img", "input", "isindex", "kbd", "label", "map", + "menu", "noframes", "noscript", "object", "ol", "p", "pre", "q", "s", + "samp", "script", "select", "small", "span", "strike", "strong", "sub", + "sup", "table", "textarea", "tt", "u", "ul", "var"], + "li"=> + ["a", "abbr", "acronym", "address", "applet", "b", "basefont", "bdo", "big", + "blockquote", "br", "button", "center", "cite", "code", "dfn", "dir", "div", + "dl", "em", "fieldset", "font", "form", "h1", "h2", "h3", "h4", "h5", "h6", + "hr", "i", "iframe", "img", "input", "isindex", "kbd", "label", "map", + "menu", "noframes", "noscript", "object", "ol", "p", "pre", "q", "s", + "samp", "script", "select", "small", "span", "strike", "strong", "sub", + "sup", "table", "textarea", "tt", "u", "ul", "var"], + "col"=>:EMPTY, + "small"=> + ["a", "abbr", "acronym", "applet", "b", "basefont", "bdo", "big", "br", + "button", "cite", "code", "dfn", "em", "font", "i", "iframe", "img", + "input", "kbd", "label", "map", "object", "q", "s", "samp", "script", + "select", "small", "span", "strike", "strong", "sub", "sup", "textarea", + "tt", "u", "var"], + "dd"=> + ["a", "abbr", "acronym", "address", "applet", "b", "basefont", "bdo", "big", + "blockquote", "br", "button", "center", "cite", "code", "dfn", "dir", "div", + "dl", "em", "fieldset", "font", "form", "h1", "h2", "h3", "h4", "h5", "h6", + "hr", "i", "iframe", "img", "input", "isindex", "kbd", "label", "map", + "menu", "noframes", "noscript", "object", "ol", "p", "pre", "q", "s", + "samp", "script", "select", "small", "span", "strike", "strong", "sub", + "sup", "table", "textarea", "tt", "u", "ul", "var"], + "i"=> + ["a", "abbr", "acronym", "applet", "b", "basefont", "bdo", "big", "br", + "button", "cite", "code", "dfn", "em", "font", "i", "iframe", "img", + "input", "kbd", "label", "map", "object", "q", "s", "samp", "script", + "select", "small", "span", "strike", "strong", "sub", "sup", "textarea", + "tt", "u", "var"], + "menu"=>["li"], + "strong"=> + ["a", "abbr", "acronym", "applet", "b", "basefont", "bdo", "big", "br", + "button", "cite", "code", "dfn", "em", "font", "i", "iframe", "img", + "input", "kbd", "label", "map", "object", "q", "s", "samp", "script", + "select", "small", "span", "strike", "strong", "sub", "sup", "textarea", + "tt", "u", "var"], + "basefont"=>:EMPTY, + "img"=>:EMPTY, + "optgroup"=>["option"], + "map"=> + ["address", "area", "blockquote", "center", "dir", "div", "dl", "fieldset", + "form", "h1", "h2", "h3", "h4", "h5", "h6", "hr", "isindex", "menu", + "noframes", "noscript", "ol", "p", "pre", "table", "ul"], + "h1"=> + ["a", "abbr", "acronym", "applet", "b", "basefont", "bdo", "big", "br", + "button", "cite", "code", "dfn", "em", "font", "i", "iframe", "img", + "input", "kbd", "label", "map", "object", "q", "s", "samp", "script", + "select", "small", "span", "strike", "strong", "sub", "sup", "textarea", + "tt", "u", "var"], + "address"=> + ["a", "abbr", "acronym", "applet", "b", "basefont", "bdo", "big", "br", + "button", "cite", "code", "dfn", "em", "font", "i", "iframe", "img", + "input", "kbd", "label", "map", "object", "p", "q", "s", "samp", "script", + "select", "small", "span", "strike", "strong", "sub", "sup", "textarea", + "tt", "u", "var"], + "sub"=> + ["a", "abbr", "acronym", "applet", "b", "basefont", "bdo", "big", "br", + "button", "cite", "code", "dfn", "em", "font", "i", "iframe", "img", + "input", "kbd", "label", "map", "object", "q", "s", "samp", "script", + "select", "small", "span", "strike", "strong", "sub", "sup", "textarea", + "tt", "u", "var"], + "param"=>:EMPTY, + "input"=>:EMPTY, + "h2"=> + ["a", "abbr", "acronym", "applet", "b", "basefont", "bdo", "big", "br", + "button", "cite", "code", "dfn", "em", "font", "i", "iframe", "img", + "input", "kbd", "label", "map", "object", "q", "s", "samp", "script", + "select", "small", "span", "strike", "strong", "sub", "sup", "textarea", + "tt", "u", "var"], + "abbr"=> + ["a", "abbr", "acronym", "applet", "b", "basefont", "bdo", "big", "br", + "button", "cite", "code", "dfn", "em", "font", "i", "iframe", "img", + "input", "kbd", "label", "map", "object", "q", "s", "samp", "script", + "select", "small", "span", "strike", "strong", "sub", "sup", "textarea", + "tt", "u", "var"], + "h3"=> + ["a", "abbr", "acronym", "applet", "b", "basefont", "bdo", "big", "br", + "button", "cite", "code", "dfn", "em", "font", "i", "iframe", "img", + "input", "kbd", "label", "map", "object", "q", "s", "samp", "script", + "select", "small", "span", "strike", "strong", "sub", "sup", "textarea", + "tt", "u", "var"], + "strike"=> + ["a", "abbr", "acronym", "applet", "b", "basefont", "bdo", "big", "br", + "button", "cite", "code", "dfn", "em", "font", "i", "iframe", "img", + "input", "kbd", "label", "map", "object", "q", "s", "samp", "script", + "select", "small", "span", "strike", "strong", "sub", "sup", "textarea", + "tt", "u", "var"], + "body"=> + ["a", "abbr", "acronym", "address", "applet", "b", "basefont", "bdo", "big", + "blockquote", "br", "button", "center", "cite", "code", "dfn", "dir", "div", + "dl", "em", "fieldset", "font", "form", "h1", "h2", "h3", "h4", "h5", "h6", + "hr", "i", "iframe", "img", "input", "isindex", "kbd", "label", "map", + "menu", "noframes", "noscript", "object", "ol", "p", "pre", "q", "s", + "samp", "script", "select", "small", "span", "strike", "strong", "sub", + "sup", "table", "textarea", "tt", "u", "ul", "var"], + "ins"=> + ["a", "abbr", "acronym", "address", "applet", "b", "basefont", "bdo", "big", + "blockquote", "br", "button", "center", "cite", "code", "dfn", "dir", "div", + "dl", "em", "fieldset", "font", "form", "h1", "h2", "h3", "h4", "h5", "h6", + "hr", "i", "iframe", "img", "input", "isindex", "kbd", "label", "map", + "menu", "noframes", "noscript", "object", "ol", "p", "pre", "q", "s", + "samp", "script", "select", "small", "span", "strike", "strong", "sub", + "sup", "table", "textarea", "tt", "u", "ul", "var"], + "button"=> + ["a", "abbr", "acronym", "address", "applet", "b", "basefont", "bdo", "big", + "blockquote", "br", "button", "center", "cite", "code", "dfn", "dir", "div", + "dl", "em", "fieldset", "font", "form", "h1", "h2", "h3", "h4", "h5", "h6", + "hr", "i", "iframe", "img", "input", "isindex", "kbd", "label", "map", + "menu", "noframes", "noscript", "object", "ol", "p", "pre", "q", "s", + "samp", "script", "select", "small", "span", "strike", "strong", "sub", + "sup", "table", "textarea", "tt", "u", "ul", "var"], + "h4"=> + ["a", "abbr", "acronym", "applet", "b", "basefont", "bdo", "big", "br", + "button", "cite", "code", "dfn", "em", "font", "i", "iframe", "img", + "input", "kbd", "label", "map", "object", "q", "s", "samp", "script", + "select", "small", "span", "strike", "strong", "sub", "sup", "textarea", + "tt", "u", "var"], + "select"=>["optgroup", "option"], + "caption"=> + ["a", "abbr", "acronym", "applet", "b", "basefont", "bdo", "big", "br", + "button", "cite", "code", "dfn", "em", "font", "i", "iframe", "img", + "input", "kbd", "label", "map", "object", "q", "s", "samp", "script", + "select", "small", "span", "strike", "strong", "sub", "sup", "textarea", + "tt", "u", "var"], + "colgroup"=>["col"], + "tr"=>["td", "th"], + "del"=> + ["a", "abbr", "acronym", "address", "applet", "b", "basefont", "bdo", "big", + "blockquote", "br", "button", "center", "cite", "code", "dfn", "dir", "div", + "dl", "em", "fieldset", "font", "form", "h1", "h2", "h3", "h4", "h5", "h6", + "hr", "i", "iframe", "img", "input", "isindex", "kbd", "label", "map", + "menu", "noframes", "noscript", "object", "ol", "p", "pre", "q", "s", + "samp", "script", "select", "small", "span", "strike", "strong", "sub", + "sup", "table", "textarea", "tt", "u", "ul", "var"], + "h5"=> + ["a", "abbr", "acronym", "applet", "b", "basefont", "bdo", "big", "br", + "button", "cite", "code", "dfn", "em", "font", "i", "iframe", "img", + "input", "kbd", "label", "map", "object", "q", "s", "samp", "script", + "select", "small", "span", "strike", "strong", "sub", "sup", "textarea", + "tt", "u", "var"], + "iframe"=> + ["a", "abbr", "acronym", "address", "applet", "b", "basefont", "bdo", "big", + "blockquote", "br", "button", "center", "cite", "code", "dfn", "dir", "div", + "dl", "em", "fieldset", "font", "form", "h1", "h2", "h3", "h4", "h5", "h6", + "hr", "i", "iframe", "img", "input", "isindex", "kbd", "label", "map", + "menu", "noframes", "noscript", "object", "ol", "p", "pre", "q", "s", + "samp", "script", "select", "small", "span", "strike", "strong", "sub", + "sup", "table", "textarea", "tt", "u", "ul", "var"]} + + ElementInclusions = +{"head"=>["link", "meta", "object", "script", "style"], "body"=>["del", "ins"]} + + ElementExclusions = +{"button"=> + ["a", "button", "fieldset", "form", "iframe", "input", "isindex", "label", + "select", "textarea"], + "a"=>["a"], + "dir"=> + ["address", "blockquote", "center", "dir", "div", "dl", "fieldset", "form", + "h1", "h2", "h3", "h4", "h5", "h6", "hr", "isindex", "menu", "noframes", + "noscript", "ol", "p", "pre", "table", "ul"], + "title"=>["link", "meta", "object", "script", "style"], + "pre"=> + ["applet", "basefont", "big", "font", "img", "object", "small", "sub", + "sup"], + "form"=>["form"], + "menu"=> + ["address", "blockquote", "center", "dir", "div", "dl", "fieldset", "form", + "h1", "h2", "h3", "h4", "h5", "h6", "hr", "isindex", "menu", "noframes", + "noscript", "ol", "p", "pre", "table", "ul"], + "label"=>["label"]} + + OmittedAttrName = +{"h6"=> + {"center"=>"align", "justify"=>"align", "left"=>"align", "ltr"=>"dir", + "right"=>"align", "rtl"=>"dir"}, + "object"=> + {"bottom"=>"align", "declare"=>"declare", "left"=>"align", "ltr"=>"dir", + "middle"=>"align", "right"=>"align", "rtl"=>"dir", "top"=>"align"}, + "dl"=>{"compact"=>"compact", "ltr"=>"dir", "rtl"=>"dir"}, + "p"=> + {"center"=>"align", "justify"=>"align", "left"=>"align", "ltr"=>"dir", + "right"=>"align", "rtl"=>"dir"}, + "acronym"=>{"ltr"=>"dir", "rtl"=>"dir"}, + "code"=>{"ltr"=>"dir", "rtl"=>"dir"}, + "ul"=> + {"circle"=>"type", "compact"=>"compact", "disc"=>"type", "ltr"=>"dir", + "rtl"=>"dir", "square"=>"type"}, + "tt"=>{"ltr"=>"dir", "rtl"=>"dir"}, + "label"=>{"ltr"=>"dir", "rtl"=>"dir"}, + "form"=>{"get"=>"method", "ltr"=>"dir", "post"=>"method", "rtl"=>"dir"}, + "q"=>{"ltr"=>"dir", "rtl"=>"dir"}, + "thead"=> + {"baseline"=>"valign", "bottom"=>"valign", "center"=>"align", + "char"=>"align", "justify"=>"align", "left"=>"align", "ltr"=>"dir", + "middle"=>"valign", "right"=>"align", "rtl"=>"dir", "top"=>"valign"}, + "area"=> + {"circle"=>"shape", "default"=>"shape", "ltr"=>"dir", "nohref"=>"nohref", + "poly"=>"shape", "rect"=>"shape", "rtl"=>"dir"}, + "td"=> + {"baseline"=>"valign", "bottom"=>"valign", "center"=>"align", + "char"=>"align", "col"=>"scope", "colgroup"=>"scope", "justify"=>"align", + "left"=>"align", "ltr"=>"dir", "middle"=>"valign", "nowrap"=>"nowrap", + "right"=>"align", "row"=>"scope", "rowgroup"=>"scope", "rtl"=>"dir", + "top"=>"valign"}, + "title"=>{"ltr"=>"dir", "rtl"=>"dir"}, + "dir"=>{"compact"=>"compact", "ltr"=>"dir", "rtl"=>"dir"}, + "s"=>{"ltr"=>"dir", "rtl"=>"dir"}, + "ol"=>{"compact"=>"compact", "ltr"=>"dir", "rtl"=>"dir"}, + "hr"=> + {"center"=>"align", "left"=>"align", "ltr"=>"dir", "noshade"=>"noshade", + "right"=>"align", "rtl"=>"dir"}, + "applet"=> + {"bottom"=>"align", "left"=>"align", "middle"=>"align", "right"=>"align", + "top"=>"align"}, + "table"=> + {"above"=>"frame", "all"=>"rules", "below"=>"frame", "border"=>"frame", + "box"=>"frame", "center"=>"align", "cols"=>"rules", "groups"=>"rules", + "hsides"=>"frame", "left"=>"align", "lhs"=>"frame", "ltr"=>"dir", + "none"=>"rules", "rhs"=>"frame", "right"=>"align", "rows"=>"rules", + "rtl"=>"dir", "void"=>"frame", "vsides"=>"frame"}, + "legend"=> + {"bottom"=>"align", "left"=>"align", "ltr"=>"dir", "right"=>"align", + "rtl"=>"dir", "top"=>"align"}, + "cite"=>{"ltr"=>"dir", "rtl"=>"dir"}, + "a"=> + {"circle"=>"shape", "default"=>"shape", "ltr"=>"dir", "poly"=>"shape", + "rect"=>"shape", "rtl"=>"dir"}, + "html"=>{"ltr"=>"dir", "rtl"=>"dir"}, + "u"=>{"ltr"=>"dir", "rtl"=>"dir"}, + "blockquote"=>{"ltr"=>"dir", "rtl"=>"dir"}, + "center"=>{"ltr"=>"dir", "rtl"=>"dir"}, + "b"=>{"ltr"=>"dir", "rtl"=>"dir"}, + "th"=> + {"baseline"=>"valign", "bottom"=>"valign", "center"=>"align", + "char"=>"align", "col"=>"scope", "colgroup"=>"scope", "justify"=>"align", + "left"=>"align", "ltr"=>"dir", "middle"=>"valign", "nowrap"=>"nowrap", + "right"=>"align", "row"=>"scope", "rowgroup"=>"scope", "rtl"=>"dir", + "top"=>"valign"}, + "link"=>{"ltr"=>"dir", "rtl"=>"dir"}, + "var"=>{"ltr"=>"dir", "rtl"=>"dir"}, + "samp"=>{"ltr"=>"dir", "rtl"=>"dir"}, + "div"=> + {"center"=>"align", "justify"=>"align", "left"=>"align", "ltr"=>"dir", + "right"=>"align", "rtl"=>"dir"}, + "textarea"=> + {"disabled"=>"disabled", "ltr"=>"dir", "readonly"=>"readonly", "rtl"=>"dir"}, + "pre"=>{"ltr"=>"dir", "rtl"=>"dir"}, + "head"=>{"ltr"=>"dir", "rtl"=>"dir"}, + "span"=>{"ltr"=>"dir", "rtl"=>"dir"}, + "br"=>{"all"=>"clear", "left"=>"clear", "none"=>"clear", "right"=>"clear"}, + "script"=>{"defer"=>"defer"}, + "noframes"=>{"ltr"=>"dir", "rtl"=>"dir"}, + "style"=>{"ltr"=>"dir", "rtl"=>"dir"}, + "meta"=>{"ltr"=>"dir", "rtl"=>"dir"}, + "dt"=>{"ltr"=>"dir", "rtl"=>"dir"}, + "option"=> + {"disabled"=>"disabled", "ltr"=>"dir", "rtl"=>"dir", "selected"=>"selected"}, + "kbd"=>{"ltr"=>"dir", "rtl"=>"dir"}, + "big"=>{"ltr"=>"dir", "rtl"=>"dir"}, + "tfoot"=> + {"baseline"=>"valign", "bottom"=>"valign", "center"=>"align", + "char"=>"align", "justify"=>"align", "left"=>"align", "ltr"=>"dir", + "middle"=>"valign", "right"=>"align", "rtl"=>"dir", "top"=>"valign"}, + "sup"=>{"ltr"=>"dir", "rtl"=>"dir"}, + "bdo"=>{"ltr"=>"dir", "rtl"=>"dir"}, + "isindex"=>{"ltr"=>"dir", "rtl"=>"dir"}, + "dfn"=>{"ltr"=>"dir", "rtl"=>"dir"}, + "fieldset"=>{"ltr"=>"dir", "rtl"=>"dir"}, + "em"=>{"ltr"=>"dir", "rtl"=>"dir"}, + "font"=>{"ltr"=>"dir", "rtl"=>"dir"}, + "tbody"=> + {"baseline"=>"valign", "bottom"=>"valign", "center"=>"align", + "char"=>"align", "justify"=>"align", "left"=>"align", "ltr"=>"dir", + "middle"=>"valign", "right"=>"align", "rtl"=>"dir", "top"=>"valign"}, + "noscript"=>{"ltr"=>"dir", "rtl"=>"dir"}, + "li"=>{"ltr"=>"dir", "rtl"=>"dir"}, + "col"=> + {"baseline"=>"valign", "bottom"=>"valign", "center"=>"align", + "char"=>"align", "justify"=>"align", "left"=>"align", "ltr"=>"dir", + "middle"=>"valign", "right"=>"align", "rtl"=>"dir", "top"=>"valign"}, + "small"=>{"ltr"=>"dir", "rtl"=>"dir"}, + "dd"=>{"ltr"=>"dir", "rtl"=>"dir"}, + "i"=>{"ltr"=>"dir", "rtl"=>"dir"}, + "menu"=>{"compact"=>"compact", "ltr"=>"dir", "rtl"=>"dir"}, + "strong"=>{"ltr"=>"dir", "rtl"=>"dir"}, + "img"=> + {"bottom"=>"align", "ismap"=>"ismap", "left"=>"align", "ltr"=>"dir", + "middle"=>"align", "right"=>"align", "rtl"=>"dir", "top"=>"align"}, + "optgroup"=>{"disabled"=>"disabled", "ltr"=>"dir", "rtl"=>"dir"}, + "map"=>{"ltr"=>"dir", "rtl"=>"dir"}, + "address"=>{"ltr"=>"dir", "rtl"=>"dir"}, + "h1"=> + {"center"=>"align", "justify"=>"align", "left"=>"align", "ltr"=>"dir", + "right"=>"align", "rtl"=>"dir"}, + "sub"=>{"ltr"=>"dir", "rtl"=>"dir"}, + "param"=>{"data"=>"valuetype", "object"=>"valuetype", "ref"=>"valuetype"}, + "input"=> + {"bottom"=>"align", "button"=>"type", "checkbox"=>"type", + "checked"=>"checked", "disabled"=>"disabled", "file"=>"type", + "hidden"=>"type", "image"=>"type", "ismap"=>"ismap", "left"=>"align", + "ltr"=>"dir", "middle"=>"align", "password"=>"type", "radio"=>"type", + "readonly"=>"readonly", "reset"=>"type", "right"=>"align", "rtl"=>"dir", + "submit"=>"type", "text"=>"type", "top"=>"align"}, + "h2"=> + {"center"=>"align", "justify"=>"align", "left"=>"align", "ltr"=>"dir", + "right"=>"align", "rtl"=>"dir"}, + "abbr"=>{"ltr"=>"dir", "rtl"=>"dir"}, + "h3"=> + {"center"=>"align", "justify"=>"align", "left"=>"align", "ltr"=>"dir", + "right"=>"align", "rtl"=>"dir"}, + "strike"=>{"ltr"=>"dir", "rtl"=>"dir"}, + "body"=>{"ltr"=>"dir", "rtl"=>"dir"}, + "ins"=>{"ltr"=>"dir", "rtl"=>"dir"}, + "button"=> + {"button"=>"type", "disabled"=>"disabled", "ltr"=>"dir", "reset"=>"type", + "rtl"=>"dir", "submit"=>"type"}, + "h4"=> + {"center"=>"align", "justify"=>"align", "left"=>"align", "ltr"=>"dir", + "right"=>"align", "rtl"=>"dir"}, + "select"=> + {"disabled"=>"disabled", "ltr"=>"dir", "multiple"=>"multiple", "rtl"=>"dir"}, + "caption"=> + {"bottom"=>"align", "left"=>"align", "ltr"=>"dir", "right"=>"align", + "rtl"=>"dir", "top"=>"align"}, + "colgroup"=> + {"baseline"=>"valign", "bottom"=>"valign", "center"=>"align", + "char"=>"align", "justify"=>"align", "left"=>"align", "ltr"=>"dir", + "middle"=>"valign", "right"=>"align", "rtl"=>"dir", "top"=>"valign"}, + "tr"=> + {"baseline"=>"valign", "bottom"=>"valign", "center"=>"align", + "char"=>"align", "justify"=>"align", "left"=>"align", "ltr"=>"dir", + "middle"=>"valign", "right"=>"align", "rtl"=>"dir", "top"=>"valign"}, + "del"=>{"ltr"=>"dir", "rtl"=>"dir"}, + "h5"=> + {"center"=>"align", "justify"=>"align", "left"=>"align", "ltr"=>"dir", + "right"=>"align", "rtl"=>"dir"}, + "iframe"=> + {"0"=>"frameborder", "1"=>"frameborder", "auto"=>"scrolling", + "bottom"=>"align", "left"=>"align", "middle"=>"align", "no"=>"scrolling", + "right"=>"align", "top"=>"align", "yes"=>"scrolling"}} + + # :startdoc: +# The code above is auto-generated. Don't edit manually. +end diff --git a/vendor/htree/htree/inspect.rb b/vendor/htree/htree/inspect.rb new file mode 100644 index 0000000..d5362d7 --- /dev/null +++ b/vendor/htree/htree/inspect.rb @@ -0,0 +1,108 @@ +require 'pp' +require 'htree/doc' +require 'htree/elem' +require 'htree/leaf' +require 'htree/tag' +require 'htree/output' +require 'htree/raw_string' + +module HTree + # :stopdoc: + class Doc + def pretty_print(q) + q.object_group(self) { @children.each {|elt| q.breakable; q.pp elt } } + end + alias inspect pretty_print_inspect + end + + class Elem + def pretty_print(q) + if @empty + q.group(1, '{emptyelem', '}') { + q.breakable; q.pp @stag + } + else + q.group(1, "{elem", "}") { + q.breakable; q.pp @stag + @children.each {|elt| q.breakable; q.pp elt } + if @etag + q.breakable; q.pp @etag + end + } + end + end + alias inspect pretty_print_inspect + end + + module Leaf + def pretty_print(q) + q.group(1, '{', '}') { + q.text self.class.name.sub(/.*::/,'').downcase + if rs = @raw_string + rs.scan(/[^\r\n]*(?:\r\n?|\n|[^\r\n]\z)/) {|line| + q.breakable + q.pp line + } + elsif self.respond_to? :display_xml + q.breakable + q.text self.display_xml('') + end + } + end + alias inspect pretty_print_inspect + end + + class Name + def inspect + if xmlns? + @local_name ? "xmlns:#{@local_name}" : "xmlns" + elsif !@namespace_uri || @namespace_uri.empty? + @local_name + elsif @namespace_prefix + "#{@namespace_prefix}{#{@namespace_uri}}#{@local_name}" + elsif @namespace_prefix == false + "-{#{@namespace_uri}}#{@local_name}" + else + "{#{@namespace_uri}}#{@local_name}" + end + end + end + + class STag + def pretty_print(q) + q.group(1, '<', '>') { + q.text @name.inspect + + @attributes.each {|n, t| + q.breakable + q.text "#{n.inspect}=\"#{t.to_attvalue_content}\"" + } + } + end + alias inspect pretty_print_inspect + end + + class ETag + def pretty_print(q) + q.group(1, '') { + q.text @qualified_name + } + end + alias inspect pretty_print_inspect + end + + class BogusETag + def pretty_print(q) + q.group(1, '{', '}') { + q.text self.class.name.sub(/.*::/,'').downcase + if rs = @raw_string + q.breakable + q.text rs + else + q.text "" + end + } + end + end + # :startdoc: +end diff --git a/vendor/htree/htree/leaf.rb b/vendor/htree/htree/leaf.rb new file mode 100644 index 0000000..243ff30 --- /dev/null +++ b/vendor/htree/htree/leaf.rb @@ -0,0 +1,92 @@ +require 'htree/modules' +require 'htree/raw_string' + +module HTree + class XMLDecl + def initialize(version, encoding=nil, standalone=nil) + init_raw_string + if /\A[a-zA-Z0-9_.:-]+\z/ !~ version + raise HTree::Error, "invalid version in XML declaration: #{version.inspect}" + end + if encoding && /\A[A-Za-z][A-Za-z0-9._-]*\z/ !~ encoding + raise HTree::Error, "invalid encoding in XML declaration: #{encoding.inspect}" + end + unless standalone == nil || standalone == true || standalone == false + raise HTree::Error, "invalid standalone document declaration in XML declaration: #{standalone.inspect}" + end + @version = version + @encoding = encoding + @standalone = standalone + end + attr_reader :version, :encoding, :standalone + end + + class DocType + def initialize(root_element_name, public_identifier=nil, system_identifier=nil) + init_raw_string + if public_identifier && /\A[ \x0d\x0aa-zA-Z0-9\-'()+,.\/:=?;!*\#@$_%]*\z/ !~ public_identifier + raise HTree::Error, "invalid public identifier in document type declaration: #{public_identifier.inspect}" + end + if system_identifier && /"/ =~ system_identifier && /'/ =~ system_identifier + raise HTree::Error, "invalid system identifier in document type declaration: #{system_identifier.inspect}" + end + + @root_element_name = root_element_name + @public_identifier = public_identifier + @system_identifier = system_identifier + end + attr_reader :root_element_name, :public_identifier, :system_identifier + end + + class ProcIns + # :stopdoc: + class << self + alias new! new + end + # :startdoc: + + def ProcIns.new(target, content) + content = content.gsub(/\?>/, '? >') if content + new! target, content + end + + def initialize(target, content) # :notnew: + init_raw_string + if content && /\?>/ =~ content + raise HTree::Error, "invalid processing instruction content: #{content.inspect}" + end + @target = target + @content = content + end + attr_reader :target, :content + end + + class Comment + # :stopdoc: + class << self + alias new! new + end + # :startdoc: + + def Comment.new(content) + content = content.gsub(/-(-+)/) { '-' + ' -' * $1.length }.sub(/-\z/, '- ') + new! content + end + + def initialize(content) # :notnew: + init_raw_string + if /--/ =~ content || /-\z/ =~ content + raise HTree::Error, "invalid comment content: #{content.inspect}" + end + @content = content + end + attr_reader :content + end + + class BogusETag + def initialize(qualified_name) + init_raw_string + @etag = ETag.new(qualified_name) + end + end +end diff --git a/vendor/htree/htree/loc.rb b/vendor/htree/htree/loc.rb new file mode 100644 index 0000000..2072f0f --- /dev/null +++ b/vendor/htree/htree/loc.rb @@ -0,0 +1,369 @@ +require 'htree/modules' +require 'htree/elem' +require 'htree/inspect' + +module HTree + module Node + # creates a location object which points to self. + def make_loc + self.class::Loc.new(nil, nil, self) + end + + # return self. + def to_node + self + end + + # +subst+ substitutes several subtrees at once. + # + # t = HTree('') + # l = t.make_loc + # t2 = t.subst({ + # l.get_subnode(0, 'k') => 'v', + # l.get_subnode(0, -1) => HTree(''), + # l.get_subnode(0, 1) => nil, + # l.get_subnode(0, 2, 0) => HTree(''), + # }) + # pp t2 + # # => + # # {emptyelem } {emptyelem } {elem {emptyelem }}}> + def subst(pairs) + pairs = pairs.map {|key, val| + key = key.index_list(self) + unless Array === val + val = [val] + end + [key, val] + } + + pairs_empty_key, pairs_nonempty_key = + pairs.partition {|key, val| key.empty? } + if !pairs_empty_key.empty? + if !pairs_nonempty_key.empty? + raise ArgumentError, "cannot substitute a node under substituting tree." + end + result = [] + pairs_empty_key.each {|key, val| result.concat val } + result.compact! + if result.length == 1 + return result[0] + else + raise ArgumentError, "cannot substitute top node by multiple nodes: #{nodes.inspect}" + end + end + if pairs_nonempty_key.empty? + return self + end + + subst_internal(pairs) + end + + def subst_internal(pairs) # :nodoc: + subnode_pairs = {} + pairs.each {|key, val| + k = key.pop + (subnode_pairs[k] ||= []) << [key, val] + } + subnode_pairs = subnode_pairs.map {|k, subpairs| + s = get_subnode(k) + subpairs_empty_key, subpairs_nonempty_key = + subpairs.partition {|key, val| key.empty? } + if !subpairs_empty_key.empty? + if !subpairs_nonempty_key.empty? + raise ArgumentError, "cannot substitute a node under substituting tree." + end + r = [] + subpairs_empty_key.each {|key, val| r.concat val } + [k, r.compact] + elsif subpairs_nonempty_key.empty? + [k, s] + else + [k, s.subst_internal(subpairs)] + end + } + subst_subnode(subnode_pairs) + end + end + + # :stopdoc: + class Doc; def node_test_string() 'doc()' end end + class Elem; def node_test_string() @stag.element_name.qualified_name end end + class Text; def node_test_string() 'text()' end end + class BogusETag; def node_test_string() 'bogus-etag()' end end + class XMLDecl; def node_test_string() 'xml-declaration()' end end + class DocType; def node_test_string() 'doctype()' end end + class ProcIns; def node_test_string() 'processing-instruction()' end end + class Comment; def node_test_string() 'comment()' end end + + module Container + def find_loc_step(index) + if index < 0 || @children.length <= index + return "*[#{index}]" + end + + return @loc_step_children[index].dup if defined? @loc_step_children + + count = {} + count.default = 0 + + steps = [] + + @children.each {|c| + node_test = c.node_test_string + count[node_test] += 1 + steps << [node_test, count[node_test]] + } + + @loc_step_children = [] + steps.each {|node_test, i| + if count[node_test] == 1 + @loc_step_children << node_test + else + @loc_step_children << "#{node_test}[#{i}]" + end + } + + return @loc_step_children[index].dup + end + end + + class Elem + def find_loc_step(index) + return super if Integer === index + if String === index + index = Name.parse_attribute_name(index, DefaultContext) + end + unless Name === index + raise TypeError, "invalid index: #{index.inspect}" + end + "@#{index.qualified_name}" + end + end + # :startdoc: +end + +class HTree::Location + def initialize(parent, index, node) # :nodoc: + if parent + @parent = parent + @index = index + @node = parent.node.get_subnode(index) + if !@node.equal?(node) + raise ArgumentError, "unexpected node" + end + else + @parent = nil + @index = nil + @node = node + end + if @node && self.class != @node.class::Loc + raise ArgumentError, "invalid location class: #{self.class} should be #{node.class::Loc}" + end + @subloc = {} + end + attr_reader :parent, :index, :node + alias to_node node + + # return self. + def make_loc + self + end + + # +top+ returns the originator location. + # + # t = HTree('') + # l = t.make_loc.get_subnode(0, 0, 0, 0) + # p l, l.top + # # => + # # + # # + def top + result = self + while result.parent + result = result.parent + end + result + end + + # +subst_itself+ substitutes the node pointed by the location. + # It returns the location of substituted node. + # + # t1 = HTree('') + # p t1 + # l1 = t1.make_loc.get_subnode(0, 0, 0, 0) + # p l1 + # l2 = l1.subst_itself(HTree('')) + # p l2 + # t2 = l2.top.to_node + # p t2 + # # => + # # {elem {elem {emptyelem }}}}> + # # + # # + # # {elem {elem {emptyelem }}}}> + # + def subst_itself(node) + if @parent + new_index = @index + if !@node + if Integer === @index + if @index < 0 + new_index = 0 + elsif @parent.to_node.children.length < @index + new_index = @parent.to_node.children.length + end + end + end + @parent.subst_itself(@parent.to_node.subst_subnode({@index=>node})).get_subnode(new_index) + else + node.make_loc + end + end + + # +subst+ substitutes several subtrees at once. + # + # t = HTree('') + # l = t.make_loc + # l2 = l.subst({ + # l.root.get_subnode('k') => 'v', + # l.root.get_subnode(-1) => HTree(''), + # l.find_element('y') => nil, + # l.find_element('z').get_subnode(0) => HTree(''), + # }) + # pp l2, l2.to_node + # # => + # # + # # {emptyelem } {emptyelem } {elem {emptyelem }}}> + def subst(pairs) + subst_itself(@node.subst(pairs)) + end + + # +loc_list+ returns an array containing from location's root to itself. + # + # t = HTree('') + # l = t.make_loc.get_subnode(0, 0, 0) + # pp l, l.loc_list + # # => + # # + # [#, + # #, + # #, + # #] + # + def loc_list + loc = self + result = [self] + while loc = loc.parent + result << loc + end + result.reverse! + result + end + + # +path+ returns the path of the location. + # + # l = HTree.parse("x").make_loc + # l = l.get_subnode(0, 0, 0) + # p l.path # => "doc()/a/b[1]/text()" + def path + result = '' + loc_list.each {|loc| + if parent = loc.parent + result << '/' << parent.node.find_loc_step(loc.index) + else + result << loc.node.node_test_string + end + } + result + end + + def index_list(node) # :nodoc: + result = [] + loc = self + while parent = loc.parent + return result if loc.to_node.equal? node + result << loc.index + loc = parent + end + return result if loc.to_node.equal? node + raise ArgumentError, "the location is not under the node: #{self.path}" + end + + # :stopdoc: + def pretty_print(q) + q.group(1, "#<#{self.class.name}", '>') { + q.text ':' + q.breakable + loc_list.each {|loc| + if parent = loc.parent + q.text '/' + q.group { q.breakable '' } + q.text parent.node.find_loc_step(loc.index) + else + q.text loc.node.node_test_string + end + } + } + end + alias inspect pretty_print_inspect + # :startdoc: +end + +module HTree::Container::Loc + # +get_subnode+ returns a location object which points to a subnode + # indexed by _index_. + def get_subnode_internal(index) # :nodoc: + return @subloc[index] if @subloc.include? index + node = @node.get_subnode(index) + if node + @subloc[index] = node.class::Loc.new(self, index, node) + else + @subloc[index] = HTree::Location.new(self, index, node) + end + end + + # +subst_subnode+ returns the location which refers the substituted tree. + # loc.subst_subnode(pairs) -> loc + # + # t = HTree('') + # l = t.make_loc.get_subnode(0, 0) + # l = l.subst_subnode({0=>HTree('')}) + # pp t, l.top.to_node + # # => + # # {elem {emptyelem }}}> + # # {elem {emptyelem }}}> + # + def subst_subnode(pairs) + self.subst_itself(@node.subst_subnode(pairs)) + end + + # +children+ returns an array of child locations. + def children + (0...@node.children.length).map {|i| get_subnode(i) } + end +end + +class HTree::Elem::Loc + def context() @node.context end + + # +element_name+ returns the name of the element name as a Name object. + def element_name() @node.element_name end + + def empty_element?() @node.empty_element? end + + # +each_attribute+ iterates over each attributes. + def each_attribute + @node.each_attribute {|attr_name, attr_text| + attr_loc = get_subnode(attr_name) + yield attr_name, attr_loc + } + end +end + +class HTree::Text::Loc + def to_s() @node.to_s end + def strip() @node.strip end + def empty?() @node.empty? end +end diff --git a/vendor/htree/htree/modules.rb b/vendor/htree/htree/modules.rb new file mode 100644 index 0000000..920fb22 --- /dev/null +++ b/vendor/htree/htree/modules.rb @@ -0,0 +1,49 @@ +module HTree + class Name; include HTree end + class Context; include HTree end + + # :stopdoc: + module Tag; include HTree end + class STag; include Tag end + class ETag; include Tag end + # :startdoc: + + module Node; include HTree end + module Container; include Node end + class Doc; include Container end + class Elem; include Container end + module Leaf; include Node end + class Text; include Leaf end + class XMLDecl; include Leaf end + class DocType; include Leaf end + class ProcIns; include Leaf end + class Comment; include Leaf end + class BogusETag; include Leaf end + + module Traverse end + module Container::Trav; include Traverse end + module Leaf::Trav; include Traverse end + class Doc; module Trav; include Container::Trav end; include Trav end + class Elem; module Trav; include Container::Trav end; include Trav end + class Text; module Trav; include Leaf::Trav end; include Trav end + class XMLDecl; module Trav; include Leaf::Trav end; include Trav end + class DocType; module Trav; include Leaf::Trav end; include Trav end + class ProcIns; module Trav; include Leaf::Trav end; include Trav end + class Comment; module Trav; include Leaf::Trav end; include Trav end + class BogusETag; module Trav; include Leaf::Trav end; include Trav end + + class Location; include HTree end + module Container::Loc end + module Leaf::Loc end + class Doc; class Loc < Location; include Trav, Container::Loc end end + class Elem; class Loc < Location; include Trav, Container::Loc end end + class Text; class Loc < Location; include Trav, Leaf::Loc end end + class XMLDecl; class Loc < Location; include Trav, Leaf::Loc end end + class DocType; class Loc < Location; include Trav, Leaf::Loc end end + class ProcIns; class Loc < Location; include Trav, Leaf::Loc end end + class Comment; class Loc < Location; include Trav, Leaf::Loc end end + class BogusETag; class Loc < Location; include Trav, Leaf::Loc end end + + class Error < StandardError; end +end + diff --git a/vendor/htree/htree/name.rb b/vendor/htree/htree/name.rb new file mode 100644 index 0000000..7364bd1 --- /dev/null +++ b/vendor/htree/htree/name.rb @@ -0,0 +1,122 @@ +require 'htree/scan' # for Pat::Nmtoken +require 'htree/context' + +module HTree + # Name represents a element name and attribute name. + # It consists of a namespace prefix, a namespace URI and a local name. + class Name +=begin +element name prefix uri localname +{u}n, n with xmlns=u nil 'u' 'n' +p{u}n, p:n with xmlns:p=u 'p' 'u' 'n' +n with xmlns='' nil '' 'n' + +attribute name +xmlns= 'xmlns' nil nil +xmlns:n= 'xmlns' nil 'n' +p{u}n=, p:n= with xmlns:p=u 'p' 'u' 'n' +n= nil '' 'n' +=end + def Name.parse_element_name(name, context) + if /\{(.*)\}/ =~ name + # "{u}n" means "use default namespace", + # "p{u}n" means "use the specified prefix p" + $` == '' ? Name.new(nil, $1, $') : Name.new($`, $1, $') + elsif /:/ =~ name && !context.namespace_uri($`).empty? + Name.new($`, context.namespace_uri($`), $') + elsif !context.namespace_uri(nil).empty? + Name.new(nil, context.namespace_uri(nil), name) + else + Name.new(nil, '', name) + end + end + + def Name.parse_attribute_name(name, context) + if name == 'xmlns' + Name.new('xmlns', nil, nil) + elsif /\Axmlns:/ =~ name + Name.new('xmlns', nil, $') + elsif /\{(.*)\}/ =~ name + case $` + when ''; Name.new(nil, $1, $') + else Name.new($`, $1, $') + end + elsif /:/ =~ name && !context.namespace_uri($`).empty? + Name.new($`, context.namespace_uri($`), $') + else + Name.new(nil, '', name) + end + end + + NameCache = {} + def Name.new(namespace_prefix, namespace_uri, local_name) + key = [namespace_prefix, namespace_uri, local_name, self] + NameCache.fetch(key) { + 0.upto(2) {|i| key[i] = key[i].dup.freeze if key[i] } + NameCache[key] = super(key[0], key[1], key[2]) + } + end + + def initialize(namespace_prefix, namespace_uri, local_name) + @namespace_prefix = namespace_prefix + @namespace_uri = namespace_uri + @local_name = local_name + if @namespace_prefix && /\A#{Pat::Nmtoken}\z/o !~ @namespace_prefix + raise HTree::Error, "invalid namespace prefix: #{@namespace_prefix.inspect}" + end + if @local_name && /\A#{Pat::Nmtoken}\z/o !~ @local_name + raise HTree::Error, "invalid local name: #{@local_name.inspect}" + end + if @namespace_prefix == 'xmlns' + unless @namespace_uri == nil + raise HTree::Error, "Name object for xmlns:* must not have namespace URI: #{@namespace_uri.inspect}" + end + else + unless String === @namespace_uri + raise HTree::Error, "invalid namespace URI: #{@namespace_uri.inspect}" + end + end + end + attr_reader :namespace_prefix, :namespace_uri, :local_name + + def xmlns? + @namespace_prefix == 'xmlns' && @namespace_uri == nil + end + + def universal_name + if @namespace_uri && !@namespace_uri.empty? + "{#{@namespace_uri}}#{@local_name}" + else + @local_name.dup + end + end + + def qualified_name + if @namespace_uri && !@namespace_uri.empty? + if @namespace_prefix + "#{@namespace_prefix}:#{@local_name}" + else + @local_name.dup + end + elsif @local_name + @local_name.dup + else + "xmlns" + end + end + + def to_s + if @namespace_uri && !@namespace_uri.empty? + if @namespace_prefix + "#{@namespace_prefix}{#{@namespace_uri}}#{@local_name}" + else + "{#{@namespace_uri}}#{@local_name}" + end + elsif @local_name + @local_name.dup + else + "xmlns" + end + end + end +end diff --git a/vendor/htree/htree/output.rb b/vendor/htree/htree/output.rb new file mode 100644 index 0000000..11e81bd --- /dev/null +++ b/vendor/htree/htree/output.rb @@ -0,0 +1,212 @@ +require 'htree/encoder' +require 'htree/doc' +require 'htree/elem' +require 'htree/leaf' +require 'htree/text' + +module HTree + # :stopdoc: + + class Text + ChRef = { + '>' => '>', + '<' => '<', + '"' => '"', + } + + def output(out, context=nil) + out.output_text @rcdata.gsub(/[<>]/) {|s| ChRef[s] } + end + + def to_attvalue_content + @rcdata.gsub(/[<>"]/) {|s| ChRef[s] } + end + + def output_attvalue(out, context) + out.output_string '"' + out.output_text to_attvalue_content + out.output_string '"' + end + + def output_cdata(out) + str = self.to_s + if %r{" + children_context + end + + def output_stag(out, context) + out.output_string '<' + @name.output(out, context) + children_context = output_attributes(out, context) + out.output_string "\n>" + children_context + end + + def output_etag(out, context) + out.output_string '" + end + end + + class Context + def output_namespaces(out, outer_context) + unknown_namespaces = {} + @namespaces.each {|prefix, uri| + outer_uri = outer_context.namespace_uri(prefix) + if outer_uri == nil + unknown_namespaces[prefix] = uri + elsif outer_uri != uri + if prefix + out.output_string " xmlns:#{prefix}=" + else + out.output_string " xmlns=" + end + Text.new(uri).output_attvalue(out, outer_context) + end + } + unless unknown_namespaces.empty? + out.output_xmlns(unknown_namespaces) + end + outer_context.subst_namespaces(@namespaces) + end + end + + class BogusETag + # don't output anything. + def output(out, context) + end + end + + class XMLDecl + # don't output anything. + def output(out, context) + end + + def output_prolog_xmldecl(out, context) + out.output_string "" + end + end + + class DocType + def output(out, context) + out.output_string "" + end + + def generate_content # :nodoc: + result = '' + if @public_identifier + result << "PUBLIC \"#{@public_identifier}\"" + else + result << "SYSTEM" + end + # Although a system identifier is not omissible in XML, + # we cannot output it if it is not given. + if @system_identifier + if /"/ !~ @system_identifier + result << " \"#{@system_identifier}\"" + else + result << " '#{@system_identifier}'" + end + end + result + end + end + + class ProcIns + def output(out, context) + out.output_string "" + end + end + + class Comment + def output(out, context) + out.output_string "" + end + end + + # :startdoc: +end diff --git a/vendor/htree/htree/parse.rb b/vendor/htree/htree/parse.rb new file mode 100644 index 0000000..dcbd815 --- /dev/null +++ b/vendor/htree/htree/parse.rb @@ -0,0 +1,410 @@ +require 'htree/scan' +require 'htree/htmlinfo' +require 'htree/text' +require 'htree/tag' +require 'htree/leaf' +require 'htree/doc' +require 'htree/elem' +require 'htree/raw_string' +require 'htree/context' +require 'htree/encoder' +require 'htree/fstr' + +module HTree + # HTree.parse parses input and return a document tree. + # represented by HTree::Doc. + # + # input should be a String or + # an object which respond to read or open method. + # For example, IO, StringIO, Pathname, URI::HTTP and URI::FTP are acceptable. + # Note that the URIs need open-uri. + # + # HTree.parse guesses input is HTML or not and XML or not. + # + # If it is guessed as HTML, the default namespace in the result is set to http://www.w3.org/1999/xhtml + # regardless of input has XML namespace declaration or not nor even it is pre-XML HTML. + # + # If it is guessed as HTML and not XML, all element and attribute names are downcaseed. + # + # If opened file or read content has charset method, + # HTree.parse decode it according to $KCODE before parsing. + # Otherwise HTree.parse assumes the character encoding of the content is + # compatible to $KCODE. + # Note that the charset method is provided by URI::HTTP with open-uri. + def HTree.parse(input) + HTree.with_frozen_string_hash { + parse_as(input, false) + } + end + + # HTree.parse_xml parses input as XML and + # return a document tree represented by HTree::Doc. + # + # It behaves almost same as HTree.parse but it assumes input is XML + # even if no XML declaration. + # The assumption causes following differences. + # * doesn't downcase element name. + # * The content of ')) + end + + def test_html_emptyelem + t = HTree.parse('') + assert_equal(HTree::Doc.new(HTree::Elem.new('{http://www.w3.org/1999/xhtml}html')), t) + assert(!t.children[0].empty_element?) + end + + def test_hr_emptyelem + t = HTree.parse('
') + assert_equal( + HTree::Doc.new( + HTree::Elem.new('{http://www.w3.org/1999/xhtml}html', + HTree::Elem.new('{http://www.w3.org/1999/xhtml}hr'))), t) + assert(t.children[0].children[0].empty_element?) + end + +end diff --git a/vendor/htree/test/test-raw_string.rb b/vendor/htree/test/test-raw_string.rb new file mode 100644 index 0000000..fce4edf --- /dev/null +++ b/vendor/htree/test/test-raw_string.rb @@ -0,0 +1,17 @@ +require 'test/unit' +require 'htree' + +class TestRawString < Test::Unit::TestCase + def test_elem + t = HTree.parse("
x") + assert_equal("x", t.root.raw_string) + assert_equal("x", t.root.raw_string) # raw_string shouldn't have side effect. + end + + def test_no_raw_string + t = HTree::Elem.new('a') + assert_equal(nil, t.raw_string) + t = HTree::Elem.new('a', HTree.parse("x").root) + assert_equal(nil, t.raw_string) + end +end diff --git a/vendor/htree/test/test-rexml.rb b/vendor/htree/test/test-rexml.rb new file mode 100644 index 0000000..ebd781e --- /dev/null +++ b/vendor/htree/test/test-rexml.rb @@ -0,0 +1,70 @@ +require 'test/unit' +require 'htree/parse' +require 'htree/rexml' +begin + require 'rexml/document' +rescue LoadError +end + +class TestREXML < Test::Unit::TestCase + def test_doc + r = HTree.parse('').to_rexml + assert_instance_of(REXML::Document, r) + end + + def test_elem + r = HTree.parse('').to_rexml + assert_instance_of(REXML::Element, e = r.root) + assert_equal('root', e.name) + assert_equal('b', e.attribute('a').to_s) + end + + def test_text + r = HTree.parse('aaa').to_rexml + assert_instance_of(REXML::Text, t = r.root.children[0]) + assert_equal('aaa', t.to_s) + end + + def test_xmldecl + s = '' + r = HTree.parse(s + 'aaa').to_rexml + assert_instance_of(REXML::XMLDecl, x = r.children[0]) + assert_equal('1.0', x.version) + assert_equal(nil, x.standalone) + + assert_instance_of(REXML::XMLDecl, HTree.parse(s).children[0].to_rexml) + end + + def test_doctype + s = '' + r = HTree.parse(s + 'xxx').to_rexml + assert_instance_of(REXML::DocType, d = r.children[0]) + assert_equal('html', d.name) + assert_equal('PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd"', d.external_id) + + assert_instance_of(REXML::DocType, HTree.parse(s).children[0].to_rexml) + end + + def test_procins + r = HTree.parse('').to_rexml + assert_instance_of(REXML::Instruction, i = r.root.children[0]) + assert_equal('xxx', i.target) + assert_equal('yyy', i.content) + + assert_instance_of(REXML::Instruction, HTree.parse('').children[0].to_rexml) + end + + def test_comment + r = HTree.parse('').to_rexml + assert_instance_of(REXML::Comment, c = r.root.children[0]) + assert_equal(' zzz ', c.to_s) + end + + def test_bogusetag + assert_equal(nil, HTree.parse('').children[0].to_rexml) + end + + def test_style + assert_equal('', HTree.parse('').to_rexml.to_s[//]) + end +end if defined? REXML diff --git a/vendor/htree/test/test-scan.rb b/vendor/htree/test/test-scan.rb new file mode 100644 index 0000000..2ed5a37 --- /dev/null +++ b/vendor/htree/test/test-scan.rb @@ -0,0 +1,153 @@ +require 'test/unit' +require 'htree/scan' + +class TestScan < Test::Unit::TestCase + def scan(str) + result = [] + HTree.scan(str) {|e| result << e } + result + end + + def test_empty + assert_equal([], scan('')) + end + + def t_single(s) + n = yield + assert_equal([n], scan(s)) + end + + def test_single + s = '' + assert_equal([[:xmldecl, s]], scan(s)) + + s = '' + assert_equal([[:doctype, s]], scan(s)) + + s = '' + assert_equal([[:procins, s]], scan(s)) + + s = '' + assert_equal([[:stag, s]], scan(s)) + s = '' + assert_equal([[:etag, s]], scan(s)) + s = '' + assert_equal([[:emptytag, s]], scan(s)) + s = '' + assert_equal([[:comment, s]], scan(s)) + s = '' + assert_equal([[:text_cdata_section, s]], scan(s)) + s = 'abc' + assert_equal([[:text_pcdata, s]], scan(s)) + end + + def test_xmldecl_seen + s0 = '' + s1 = '' + assert_equal([[:stag, s1]], scan(s1)) + assert_equal([[:xmldecl, s0], [:stag, s1]], scan(s0 + s1)) + end + + def test_cdata_content + s = '' + assert_equal([ + [:stag, ''], + [:stag, ''], + [:stag, ''], + ], scan(s)) + + s = '\nd\n\ne" + assert_equal([ + [:stag, ""], + [:text_pcdata, "a\n"], + [:stag, ""], + [:text_pcdata, "\nb\n"], + [:stag, ""], + [:text_pcdata, "\nd\n"], + [:etag, ""], + [:text_pcdata, "\ne"], + ], scan(s)) + + end + + def test_eol_xml + # In XML, line breaks are treated as part of content. + # It's because KEEPRSRE is yes in XML. + # http://www.satoshii.org/markup/websgml/valid-xml#keeprsre + s = "a\n\nb\n\nc\n\nd\n\ne" + assert_equal([ + [:xmldecl, ""], + [:text_pcdata, "a\n"], + [:stag, ""], + [:text_pcdata, "\nb\n"], + [:stag, ""], + [:text_pcdata, "\nc\n"], + [:etag, ""], + [:text_pcdata, "\nd\n"], + [:etag, ""], + [:text_pcdata, "\ne"], + ], scan(s)) + end + + def test_xml_html_detection + assert_equal([false, true], HTree.scan("") {}) + assert_equal([true, false], HTree.scan("") {}) + assert_equal([true, true], HTree.scan('') {}) + end + + def test_quoted_attr + assert_equal([[:emptytag, '']], scan('')) + end + + def test_bare_slash + assert_equal([[:stag, '']], scan('')) + assert_equal([[:stag, '']], scan('')) + end + +end diff --git a/vendor/htree/test/test-security.rb b/vendor/htree/test/test-security.rb new file mode 100644 index 0000000..398532c --- /dev/null +++ b/vendor/htree/test/test-security.rb @@ -0,0 +1,37 @@ +require 'test/unit' +require 'htree/parse' +require 'htree/template' +require 'pathname' + +class TestSecurity < Test::Unit::TestCase + def safe(n) + assert_equal(0, $SAFE) + Thread.new { + $SAFE = n + assert_equal(n, $SAFE) + yield + }.join + assert_equal(0, $SAFE) + end + + def test_parse + safe(1) { + assert_equal(1, $SAFE) + assert_nothing_raised { HTree.parse("") } + assert_raise(SecurityError) { HTree.parse("".taint) } + } + assert_nothing_raised { HTree.parse("") } + assert_nothing_raised { HTree.parse("".taint) } + end + + def test_template + safe(1) { + assert_nothing_raised { HTree.expand_template("/dev/null", nil, '') } + assert_raise(SecurityError) { HTree.expand_template("/dev/null".taint, nil, '') } + } + assert_nothing_raised { HTree.expand_template("/dev/null", nil, '') } + assert_nothing_raised { HTree.expand_template("/dev/null".taint, nil, '') } + end + +end + diff --git a/vendor/htree/test/test-subnode.rb b/vendor/htree/test/test-subnode.rb new file mode 100644 index 0000000..ecaea9f --- /dev/null +++ b/vendor/htree/test/test-subnode.rb @@ -0,0 +1,142 @@ +require 'test/unit' +require 'htree' + +class TestSubnode < Test::Unit::TestCase + def test_elem_get + e1 = HTree.parse("abc").root + assert_equal(HTree::Text.new("x"), e1.get_subnode("href")) + assert_equal(HTree::Text.new("abc"), e1.get_subnode(0)) + end + + def test_elem_subst + e1 = HTree.parse_xml("abc").root + e2 = e1.subst_subnode("href"=>"xxx", 0=>"def") + assert_equal("a", e2.name) + assert_equal("xxx", e2.fetch_attr("href")) + assert_equal([HTree::Text.new("def")], e2.children) + assert_equal([], e1.subst_subnode(0=>nil).children) + end + + def test_elem_subst_empty + e1 = HTree.parse("").root + assert_equal(true, e1.empty_element?) + assert_equal(true, e1.subst_subnode("src"=>"xxx").empty_element?) + assert_equal(false, e1.subst_subnode(0=>"xxx").empty_element?) + end + + def test_elem_multiple_attr_value + h = {"b"=>"c", HTree::Name.new(nil, "", "b")=>"d"} + assert_match(/\A(cd|dc)\z/, + HTree::Elem.new("a").subst_subnode(h).get_subnode('b').to_s) + + a = [["b","c"], [HTree::Name.new(nil, "", "b"),"d"]] + assert_equal('cd', + HTree::Elem.new("a").subst_subnode(a).get_subnode('b').to_s) + assert_equal('dc', + HTree::Elem.new("a").subst_subnode(a.reverse).get_subnode('b').to_s) + end + + def test_elem_subst_outrange + e1 = HTree("abc").root + e2 = e1.subst_subnode(-1=>HTree(''), 1=>HTree('')) + assert_equal(HTree('abc').root, e2) + end + + def test_doc_subst_outrange + d1 = HTree("abc") + d2 = d1.subst_subnode(-1=>HTree(''), 1=>HTree('')) + assert_equal(HTree('abc'), d2) + end + + def test_doc_get + doc = HTree.parse("abc ") + assert_equal(doc.root, doc.get_subnode(1)) + end + + def test_doc_subst + doc1 = HTree.parse("abc ") + doc2 = doc1.subst_subnode(1=>"yy") + assert_equal(HTree::Text.new("yy"), doc2.children[1]) + assert_equal([], doc1.subst_subnode(0=>nil, 1=>nil, 2=>nil).children) + end + + def test_doc_loc + d1 = HTree.parse("a") + d2 = HTree.parse("") + assert_equal(d2, d1.subst_subnode(0=>d2.make_loc)) + end + + def test_doc + e = HTree.parse("a").root + d = HTree.parse("") + r = HTree('').root + assert_equal(r, e.subst_subnode(0=>d)) + assert_equal(r, e.subst_subnode(0=>d.make_loc)) + assert_equal(r, e.subst_subnode(0=>[d])) + assert_equal(r, e.subst_subnode(0=>[d.make_loc])) + end + + def test_doc2 + e = HTree.parse("a") + d = HTree.parse("") + r = HTree('') + assert_equal(r, e.subst_subnode(0=>d)) + assert_equal(r, e.subst_subnode(0=>d.make_loc)) + assert_equal(r, e.subst_subnode(0=>[d])) + assert_equal(r, e.subst_subnode(0=>[d.make_loc])) + end + + def test_change_by_subst_itself + l = HTree("a").make_loc + l2 = l.get_subnode(0, 0).subst_itself('x') + assert_equal(HTree::Text.new('x'), l2.to_node) + assert_equal(HTree('x'), l2.top.to_node) + l2 = l.get_subnode(0).subst_itself('xxx') + assert_equal(HTree::Text.new('xxx'), l2.to_node) + assert_equal(HTree('xxx'), l2.top.to_node) + end + + def test_add_by_subst_itself + l = HTree("a").make_loc + l2 = l.get_subnode(0, 'x').subst_itself('y') + assert_equal(HTree::Text.new('y'), l2.to_node) + assert_equal(HTree('a'), l2.top.to_node) + l2 = l.get_subnode(0, 0).subst_itself('b') + assert_equal(HTree::Text.new('b'), l2.to_node) + assert_equal(HTree('b'), l2.top.to_node) + xmldecl = HTree('').get_subnode(0) + l2 = l.get_subnode(-1).subst_itself(xmldecl) + assert_equal(0, l2.index) + assert_equal(xmldecl, l2.to_node) + assert_equal(HTree('a'), l2.top.to_node) + procins = HTree('').get_subnode(0) + l2 = l.get_subnode(10).subst_itself(procins) + assert_equal(1, l2.index) + assert_equal(procins, l2.to_node) + assert_equal(HTree('a'), l2.top.to_node) + end + + def test_del_by_subst_itself + l = HTree("y").make_loc + l2 = l.get_subnode(0, 'x').subst_itself(nil) + assert_equal(nil, l2.to_node) + assert_equal(HTree('y'), l2.top.to_node) + l2 = l.get_subnode(0, 1).subst_itself(nil) + assert_equal(HTree(''), l2.top.to_node) + l = HTree('').make_loc + l2 = l.get_subnode(0).subst_itself(nil) + assert_equal(HTree(''), l2.top.to_node) + end + + def test_subst + l = HTree('').make_loc + assert_equal(HTree("xa"), + l.to_node.subst({ + l.get_subnode(0) => nil, + l.get_subnode(1, 0) => 'x', + l.get_subnode(1, 1, 0) => 'a', + l.get_subnode(1, 2, 'k') => 'v' + })) + end + +end diff --git a/vendor/htree/test/test-template.rb b/vendor/htree/test/test-template.rb new file mode 100644 index 0000000..96bb1ff --- /dev/null +++ b/vendor/htree/test/test-template.rb @@ -0,0 +1,287 @@ +require 'test/unit' +require 'htree/template' +require 'stringio' + +class TestTemplate < Test::Unit::TestCase + Decl = '' + + def assert_xhtml(expected, template, message=nil) + prefix = '' + + "" + suffix = "" + result = HTree.expand_template(''){"#{template}"} + assert_match(/\A#{Regexp.quote prefix}/, result) + assert_match(/#{Regexp.quote suffix}\z/, result) + result = result[prefix.length..(-suffix.length-1)] + assert_equal(expected, result, message) + end + + def test_text + assert_xhtml("1", 'd') + assert_xhtml('1', 'd') + assert_xhtml("1", 'd') + assert_xhtml("abc", %q{ac}) + end + + def test_tree + assert_xhtml("x", 'd') + assert_xhtml("x", 'd') + end + + def test_attr + assert_xhtml("d", 'd') + assert_xhtml("d", 'd') + assert_xhtml("d", 'd') + end + + def test_if + assert_xhtml("d", 'd') + assert_xhtml('', 'd') + assert_xhtml("dd", 'ddd') + + assert_xhtml('d', 'd') + end + + def test_iter + assert_xhtml("123", + '') + assert_xhtml("123", + '') + end + + def test_iter_content + assert_xhtml("123", + '') + assert_xhtml("123", + '') + end + + def test_iter_local_template + assert_xhtml("123", + '') + end + + def test_call + assert_xhtml("1", + '') + end + + def test_template + assert_xhtml('d', + 'd') + end + + def test_file + assert_equal(<<'End'.chop, +aaa +End + HTree.expand_template("#{File.dirname __FILE__}/template.html", "aaa", '')) + end + + def test_whitespace + assert_xhtml("", ' ') + assert_xhtml(" ", ' ') + assert_xhtml(" ", '
 
') + assert_xhtml(" ", %q{ }) + assert_xhtml(" ", %q{}) + end + + def test_ignorable + assert_xhtml("a", '
a
') + assert_xhtml("a", 'a') + end + + def test_template_in_attr + assert_xhtml("", '') + end + + def test_empty_block_argument + assert_xhtml("vv", 'v') + end + + def test_empty_element + assert_xhtml("", '') # 2004-06-10: reported by Takuo KITAME + assert_xhtml("", '') + assert_xhtml("", '') + assert_xhtml("", '') + assert_xhtml("", '') + assert_xhtml("", '') + assert_xhtml("", '') + assert_xhtml("", '') + end + + def test_empty_element_start_end_tag + assert_xhtml("", '') + assert_xhtml("", '') + assert_xhtml("", '') + assert_xhtml("", '') + assert_xhtml("", '') + assert_xhtml("", '') + assert_xhtml("", '') + assert_xhtml("", '') + end + + def test_toplevel_local_variable + eval("htree_test_toplevel_local_variable = :non_modified_value", TOPLEVEL_BINDING) + HTree.expand_template("#{File.dirname __FILE__}/assign.html", "aaa", '') + assert_equal(:non_modified_value, eval("htree_test_toplevel_local_variable", TOPLEVEL_BINDING)) + eval("htree_test_toplevel_local_variable = 1", TOPLEVEL_BINDING) + end + + def test_extend_compiled_template + m = HTree.compile_template('
self is
') + o = "zzz" + o.extend m + assert_equal('self is "zzz"', + HTree.expand_template(''){'
'}) + end + + def test_attr_nbsp + @t = HTree::Text.parse_pcdata(' ') + assert_xhtml("d", 'd') + end + + def test_text_nbsp + @t = HTree::Text.parse_pcdata(' ') + assert_xhtml(" ", 'd') + end + + def test_content_text + assert_xhtml("ab", '"a"+"b"') + assert_xhtml("2", '1+1') + end + +end + +class MemFile + def initialize(str) + @str = str + end + + def read + @str + end +end + +class TestTemplateScopeObj + Const = 'good_const' + @@cvar = 'good_cvar' + def initialize + @ivar = 'good_ivar' + end +end + +class TestTemplateScope < Test::Unit::TestCase + Const = 'bad_const' + @@cvar = 'bad_cvar' + def setup + @ivar = 'bad_ivar' + eval("test_local_variable = 'bad_lvar'", TOPLEVEL_BINDING) + end + + XMLDeclStr = '' + + def test_expand_template + obj = TestTemplateScopeObj.new + assert_equal("#{XMLDeclStr}[TestTemplateScopeObj]", + HTree.expand_template(MemFile.new(''), obj, '')) + assert_equal("#{XMLDeclStr}good_ivar", + HTree.expand_template(MemFile.new(''), obj, '')) + assert_equal("#{XMLDeclStr}good_cvar", + HTree.expand_template(MemFile.new(''), obj, '')) + assert_equal("#{XMLDeclStr}good_const", + HTree.expand_template(MemFile.new(''), obj, '')) + test_local_variable = 'bad_lvar' + assert_equal("#{XMLDeclStr}good_lvar", + HTree.expand_template(MemFile.new(''), obj, '')) + end + + def test_compile_template + obj = TestTemplateScopeObj.new + mod = HTree.compile_template(MemFile.new(<<-'End')) + + + + + End + mod.module_eval <<-'End' + Const = 'mod_const' + @@cvar = 'mod_cvar' + @ivar = 'mod_ivar' + End + assert_equal("[#{mod.inspect}]", mod.test_nesting.extract_text.to_s) + assert_equal("mod_const", mod.test_const.extract_text.to_s) + assert_equal("mod_cvar", mod.test_cvar.extract_text.to_s) + assert_equal("mod_ivar", mod.test_ivar.extract_text.to_s) + obj = Object.new + obj.instance_variable_set :@ivar, 'obj_ivar' + obj.extend mod + assert_equal("[#{mod.inspect}]", obj.__send__(:test_nesting).extract_text.to_s) + assert_equal("mod_const", obj.__send__(:test_const).extract_text.to_s) + assert_equal("mod_cvar", obj.__send__(:test_cvar).extract_text.to_s) + assert_equal("obj_ivar", obj.__send__(:test_ivar).extract_text.to_s) + end +end + +class TestCDATA < Test::Unit::TestCase + def test_html_script + v = "x", + HTree.expand_template('') {""}.gsub(/\n/, '')) + end + + def test_xml_script + v = "x", + HTree.expand_template('') {""}.gsub(/\n/, '')) + end + + def test_html_script_invalid_content + v = "x"} + } + end +end + +class TestCharset < Test::Unit::TestCase + class CharsetString < String + attr_accessor :charset + end + + def with_kcode(kcode) + old_kcode = $KCODE + begin + $KCODE = kcode + yield + ensure + $KCODE = old_kcode + end + end + + def test_us_ascii + with_kcode('E') { + out = HTree.expand_template(CharsetString.new) { "abc" } + assert_equal(out.charset, 'US-ASCII') + } + end + + def test_euc_jp + with_kcode('E') { + out = HTree.expand_template(CharsetString.new) { "\xa1\xa1" } + assert_equal(out.charset, 'EUC-JP') + } + end +end + +class TestTemplateDOCTYPE < Test::Unit::TestCase + def test_html + assert_equal( + '', + HTree.expand_template('') {''}.gsub(/\n/, '')) + end +end diff --git a/vendor/htree/test/test-text.rb b/vendor/htree/test/test-text.rb new file mode 100644 index 0000000..b73e674 --- /dev/null +++ b/vendor/htree/test/test-text.rb @@ -0,0 +1,35 @@ +require 'test/unit' +require 'htree/text' + +class TestText < Test::Unit::TestCase + def test_new + assert_equal("abc&amp;def", HTree::Text.new("abc&def").rcdata) + end + +=begin + def test_parse + assert_equal("abc&def", HTree::Text.parse("abc&def").rcdata) + end + + def test_to_s + assert_equal("abc&def", HTree::Text.parse("abc&def").to_s) + end +=end + + def kcode(kc) + old = $KCODE + begin + $KCODE = kc + yield + ensure + $KCODE = old + end + end + + def test_normalize + kcode('EUC') { + assert_equal("x').make_loc + l2 = l.filter {|n| n.path != 'doc()/a/b[1]' } + assert_equal(HTree.parse(''), l2) + end + + def test_title + inputs = [ + HTree.parse('aaa'), + HTree.parse(<<'End') + + + aaa + + +End + ] + result = HTree::Text.new('aaa') + + inputs.each {|input| + assert_equal(result, input.title) + } + + inputs.each {|input| + assert_equal(result, input.make_loc.title) + } + + end + + def test_author + inputs = [ + HTree.parse(''), + HTree.parse(''), + HTree.parse(<<'End'), + + + xxx + + +End + HTree.parse(<<'End') + + + xxx + + +End + ] + result = HTree::Text.new('xxx') + inputs.each {|input| + #assert_equal(result, input.author) + } + inputs.each {|input| + assert_equal(result, input.make_loc.author) + } + end +end