# :stopdoc: require 'htree/modules' require 'htree/container' module HTree class Doc class << self alias new! new end # 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 # :startdoc: