Class: Xbd::Tag

Inherits:
Object
  • Object
show all
Defined in:
lib/xbd/xbd_tag.rb

Overview

********************************* Xbd::Tag object *********************************

Consists of:

name:     a string
attrs:    a Hash of Attributes, String -> String
tags:     an ordered Array of Tag objects

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(name, attrs = nil, tags = nil) {|_self| ... } ⇒ Tag

Returns a new instance of Tag.

Yields:

  • (_self)

Yield Parameters:

  • _self (Xbd::Tag)

    the object that the method was called on



12
13
14
15
16
17
18
19
# File 'lib/xbd/xbd_tag.rb', line 12

def initialize(name,attrs=nil,tags=nil,&block)
  @name=name.to_s
  @attrs={}
  attrs.each {|k,v|@attrs[k.to_s]=v.to_s} if attrs
  @tags=[]
  self<<tags if tags
  yield self if block
end

Instance Attribute Details

#attrsObject (readonly)

************************************************************ Access Attrs ************************************************************



29
30
31
# File 'lib/xbd/xbd_tag.rb', line 29

def attrs
  @attrs
end

#tagsObject (readonly)

************************************************************ Access Tags ************************************************************ return tags array



37
38
39
# File 'lib/xbd/xbd_tag.rb', line 37

def tags
  @tags
end

Class Method Details

.parse(source, index, tagsd, attrsd, valuesd) ⇒ Object

********************************************************** Load XBD Tag Data from String ********************************************************** parse a Tag, all its Attributes and all its Sub-tags recursively.

inputs:

source - source binary string
index - offset to start reading at
tagsd - tag-names dictionary
attrsd - attribute-names dictionary
valuesd - attribute-values dictionary

returns the Tag object generated AND the first “index” in the string after read tag-data



151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
# File 'lib/xbd/xbd_tag.rb', line 151

def Tag.parse(source,index,tagsd,attrsd,valuesd)
  tag_length,index=Asi.read_asi(source,index)
  tag_start_index=index

  # read tag name
  tag_name_id,index=Asi.read_asi(source,index)
  tag_name=tagsd[tag_name_id]
  raise "tag name id(#{tag_name_id}) not in tag-names dictionary" if !tag_name

  # read attributes
  attr_byte_size,index=Asi.read_asi(source,index)
  attrs_hash={}
  while attr_byte_size>0
    i=index
    name_id,index=Asi.read_asi(source,index)
    value_id,index=Asi.read_asi(source,index)
    attr_byte_size-=(index-i)
    n=attrsd[name_id]
    v=valuesd[value_id]
    raise "attribute name id(#{name_id}) not in attribute-names dictionary (max value = #{attrsd.length})" if !n
    raise "attribute value id(#{value_id}) not in attribute-values dictionary (max value = #{valuesd.length})" if !v
    attrs_hash[n]=v
  end
  tag_length-=(index-tag_start_index)

  # read sub-tags
  tags=[]
  while tag_length>0
    i=index
    node,index=Tag.parse(source,index,tagsd,attrsd,valuesd)
    tags<<node
    tag_length-=(index-i)
  end
  return Tag.new(tag_name,attrs_hash,tags),index
end

Instance Method Details

#<<(tag) ⇒ Object

Add sub-tag or array of sub-tags



65
66
67
68
69
70
71
# File 'lib/xbd/xbd_tag.rb', line 65

def <<(tag)
  return unless tag # ignore nil
  tags= tag.kind_of?(Array) ? tag : [tag]
  tags.each {|t| raise "All sub-tags in must be #{self.class} objects. Attempted to add #{t.class} object." unless t.kind_of?(self.class)}
  @tags+=tags
  tag
end

#==(tag) ⇒ Object



73
74
75
76
77
# File 'lib/xbd/xbd_tag.rb', line 73

def ==(tag)
  name==tag.name &&
  attrs==tag.attrs &&
  tags==tag.tags
end

#[](attr) ⇒ Object



30
# File 'lib/xbd/xbd_tag.rb', line 30

def [](attr) @attrs[attr.to_s] end

#[]=(attr, val) ⇒ Object



31
# File 'lib/xbd/xbd_tag.rb', line 31

def []=(attr,val) val==nil ? @attrs.delete(attr.to_s) : @attrs[attr.to_s]=val.to_s end

#each_attributeObject



53
54
55
# File 'lib/xbd/xbd_tag.rb', line 53

def each_attribute
  @attrs.each {|k,v| yield k,v}
end

#each_tag(name = nil) ⇒ Object

iterate over all tags or only with matching names



58
59
60
61
62
# File 'lib/xbd/xbd_tag.rb', line 58

def each_tag(name=nil)
  tags.each do |tag|
    yield tag if !name || tag.name==name
  end
end

#inspectObject



100
101
102
# File 'lib/xbd/xbd_tag.rb', line 100

def inspect
  to_s("",32)
end

#nameObject

************************************************************ Access Name ************************************************************



23
# File 'lib/xbd/xbd_tag.rb', line 23

def name() @name end

#name=(n) ⇒ Object



24
# File 'lib/xbd/xbd_tag.rb', line 24

def name=(n) @name=n end

#populate_dictionaries(tagsd, attrsd, valuesd) ⇒ Object

************************************************************ to binary XBD support methods ************************************************************



112
113
114
115
116
# File 'lib/xbd/xbd_tag.rb', line 112

def populate_dictionaries(tagsd,attrsd,valuesd)
  tagsd<<name                                                       # add this tag's name
  attrs.each {|k,v| attrsd<<k; valuesd<<v}                           # add all attribute names and values
  tags.each {|tag| tag.populate_dictionaries(tagsd,attrsd,valuesd)} # recurse on sub-tags
end

#tag(names) ⇒ Object

returns first tag that matches name names can be a “/” delimited path string OR an array of exact string values to match (in case you want to match “/” in a tag name)



43
44
45
46
47
48
49
50
51
# File 'lib/xbd/xbd_tag.rb', line 43

def tag(names)
  return self if !names || (names.kind_of?(Array) && names.length==0)
  names=names.split("/") unless names.kind_of?(Array)
  name=names[0]
  tags.each do |tag|
    return tag.tag(names[1..-1]) if tag.name==name
  end
  return nil
end

#tagnamesObject



38
# File 'lib/xbd/xbd_tag.rb', line 38

def tagnames() @tags.collect {|t| t.name} end

#to_binaryObject

************************************************************ to binary XBD (to_xbd) ************************************************************ use this to convert an xbd tag structure into a saveable xbd file-string



134
135
136
137
# File 'lib/xbd/xbd_tag.rb', line 134

def to_binary
  populate_dictionaries(tagsd=Dictionary.new, attrsd=Dictionary.new, valuesd=Dictionary.new)
  Xbd::SBDXML_HEADER + tagsd.to_binary + attrsd.to_binary + valuesd.to_binary + to_binary_partial(tagsd,attrsd,valuesd)
end

#to_binary_partial(tagsd, attrsd, valuesd) ⇒ Object

encode just this tag in binary Note this returned value alone is not parsable



120
121
122
123
124
125
126
127
128
# File 'lib/xbd/xbd_tag.rb', line 120

def to_binary_partial(tagsd,attrsd,valuesd)
  # build attrs_data string: all attr name-value pairs as ASIs concatinated
  attrs_data=attrs.keys.sort.collect {|key| attrsd[key].to_asi + valuesd[attrs[key]].to_asi}.join

  data=tagsd[name].to_asi +                                         # name asi
    attrs_data.length.to_asi + attrs_data +                         # attrs length asi and attrs
    tags.collect {|tag| tag.to_binary_partial(tagsd,attrsd,valuesd)}.join   # sub-tags
  data.to_asi_string                                                # tag data pre-pended with tag-data length asi
end

#to_rubyObject

convert to basic ruby data structure



105
106
107
# File 'lib/xbd/xbd_tag.rb', line 105

def to_ruby
  {:name=>name, :attrs=>@attrs.clone, :tags=>tags.collect {|tag|tag.to_ruby}}
end

#to_s(indent = "", max_attr_value_length = nil) ⇒ Object Also known as: to_xml

************************************************************ to XML (to_s) ************************************************************



82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
# File 'lib/xbd/xbd_tag.rb', line 82

def to_s(indent="",max_attr_value_length=nil)
  a=[name]
  attrs.keys.sort.each do |k|
    v=attrs[k]
    v=v[0..max_attr_value_length-1] if max_attr_value_length
    a<<"#{k}=\"#{Xbd.xml_escape(v)}\""
  end
  ret="#{indent}<#{a.join(' ')}"
  if tags.length>0
    ret+=">\n"
    tags.each {|st| ret+=st.to_s(indent+"    ",max_attr_value_length)}
    ret+="#{indent}</#{name}>\n"
  else
    ret+="/>\n"
  end
end