Class: VORuby::HomogeneousNodeList

Inherits:
Object
  • Object
show all
Includes:
Enumerable
Defined in:
lib/voruby.rb

Overview

An array-like class that uses an XML::Node to back itself. Designed to work in concert with a VOTable::Base object or at least something with a node method and a new method that takes a XML::Node object. Mixes in Enumerable for added functionality.

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(node, xpath, klass) ⇒ HomogeneousNodeList

Create a new node list. node is the XML::Node that all operation will be mirrored on. xpath is the the XPath expression used to retrieve the children of node that make up the list. klass is the class of those children.

vot = VOTable.new({
 :version => '1.1',
 :id => 'my_test_votable',
 :description => Description.new,
 :definitions => Definitions.new,
 :coordinate_systems => [Coosys.new],
 :params => [Param.new],
 :infos => [Info.new],
 :resources => [Resource.new]
})
node_list = HomogeneousNodeList.new(vot, 'COOSYS', VOTable::V_1::Coosys)


47
48
49
50
51
# File 'lib/voruby.rb', line 47

def initialize(node, xpath, klass)
  @node = node.is_a?(XML::Node) ? node : node.node
  @xpath = xpath
  @klass = klass
end

Instance Attribute Details

#klassObject (readonly)

The class of the sub-objects allowed in the list.



28
29
30
# File 'lib/voruby.rb', line 28

def klass
  @klass
end

#xpathObject (readonly)

The XPath expression to the child node(s) of the list.



25
26
27
# File 'lib/voruby.rb', line 25

def xpath
  @xpath
end

Instance Method Details

#<<(obj) ⇒ Object

Append a new member to the end of the list.

node_list << Coosys.new


75
76
77
78
79
80
81
82
# File 'lib/voruby.rb', line 75

def <<(obj)
  raise "Expected item of type #{@klass} but was #{obj.class}" if !obj.is_a?(@klass)
  
  obj.node.name = self.xpath.first.split(':').last if self.xpath.is_a?(Array)
  
  last_in_list = @node.find_first("*[local-name()='#{obj.node.name}'][last()]")
  last_in_list ? last_in_list.next = obj.node : @node.child_add(obj.node)
end

#==(obj) ⇒ Object

Two lists are equivalent if their lengths are equal and the members of the lists are equal to each other (and in the same order).



175
176
177
178
179
180
181
182
183
# File 'lib/voruby.rb', line 175

def ==(obj)
  return false if self.length != obj.length
  
  self.each_with_index do |item, i|
    return false if obj[i] != item
  end
  
  true
end

#[](i) ⇒ Object

Retrieve the ith member of the list. i may be less than one.

coosys2 = node_list[1]


97
98
99
100
101
102
103
104
105
# File 'lib/voruby.rb', line 97

def [](i)
  i = self.length + i if i < 0 # support negative indices
  
  expr = self.xpath.is_a?(Array) ?
     ["#{self.xpath.first}[#{i+1}]", self.xpath.last] :
     ["#{self.xpath}[#{i+1}]"]
  
  klass.new(@node.find_first(*expr))
end

#[]=(i, obj) ⇒ Object

Set the ith member of the list. Setting a member to a location longer than the current list, appends that member to the end of the list. In other words, there are no nil members allowed.

node_list[1] = Coosys.new


111
112
113
114
115
116
117
118
119
120
121
122
123
124
# File 'lib/voruby.rb', line 111

def []=(i, obj)
  raise "Expected item of type #{@klass} but was #{obj.class}" if !obj.is_a?(@klass)
  
  i = self.length + i if i < 0 # support negative indices
  
  expr = self.xpath.is_a?(Array) ?
    ["#{self.xpath.first}[#{i+1}]", self.xpath.last] :
    ["#{self.xpath}[#{i+1}]"]
  
  obj.node.name = self.xpath.first.split(':').last if self.xpath.is_a?(Array)
  
  this_node = @node.find_first(*expr)
  this_node ? this_node.replace_with(obj.node) : self << obj
end

#clearObject

Clear the list of all its members.

node_list.clear


137
138
139
140
141
# File 'lib/voruby.rb', line 137

def clear
  @node.find(*self.xpath).each do |el|
    el.remove!
  end
end

#delete_at(i) ⇒ Object

Delete the ith member in the list.

node_list.delete_at(1)  # delete the second coordinate system


128
129
130
131
132
133
# File 'lib/voruby.rb', line 128

def delete_at(i)
  expr = self.xpath.is_a?(Array) ?
    ["#{self.xpath.first}[#{i+1}]", self.xpath.last] :
    ["#{self.xpath}[#{i+1}]"]
  @node.find_first(*expr).remove!
end

#eachObject

Iterate through each member of the list.

node_list.each do |obj|
  puts obj
end


57
58
59
60
61
# File 'lib/voruby.rb', line 57

def each
  @node.find(*self.xpath).each do |e|
    yield klass.new(e)
  end
end

#firstObject

Pick the first member of the list.

coosys1 = node_list.first


145
146
147
148
149
150
# File 'lib/voruby.rb', line 145

def first
  expr = self.xpath.is_a?(Array) ?
    ["#{self.xpath.first}[1]", self.xpath.last] :
    ["#{self.xpath}[1]"]
  klass.new(@node.find_first(*expr))
end

#lastObject

Pick the last member of the list

coosys_last = node_list.last


154
155
156
157
158
159
# File 'lib/voruby.rb', line 154

def last
  expr = self.xpath.is_a?(Array) ?
    ["#{self.xpath.first}[last()]", self.xpath.last] :
    ["#{self.xpath}[last()]"]
  klass.new(@node.find_first(*expr))
end

#lengthObject

Find the number of members in the list.

node_list.length  # => 4


163
164
165
# File 'lib/voruby.rb', line 163

def length
  @node.find(*self.xpath).length
end

#prepend(obj) ⇒ Object

Prepend a new member to the beginning of the list.

node_list.prepend(Coosys.new)


86
87
88
89
90
91
92
93
# File 'lib/voruby.rb', line 86

def prepend(obj)
  raise "Expected item of type #{@klass} but was #{obj.class}" if !obj.is_a?(@klass)
  
  obj.node.name = self.xpath.first.split(':').last if self.xpath.is_a?(Array)
  
  first_in_list = @node.find_first("*[local-name()='#{obj.node.name}'][1]")
  first_in_list ? first_in_list.prev = obj.node : @node.child_add(obj.node)
end

#replace(*args) ⇒ Object

Replace the current member of the list with those specified.

node_list.replace(Coosys.new, Coosys.new, Coosys.new)


66
67
68
69
70
71
# File 'lib/voruby.rb', line 66

def replace(*args)
  self.clear
  args.flatten.each do |a|
    self << a
  end
end

#sizeObject

Alias for #length.



168
169
170
# File 'lib/voruby.rb', line 168

def size
  length
end