Class: Treebank::Node

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

Overview

A node in a tree

A Node consists of a label, which may be any arbitrary Object, and a list of children, which are also Node objects.

Direct Known Subclasses

ParentedNode

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(label = nil, child_labels = []) ⇒ Node

Create a node, specifying its label and its children’s labels.

label

The label of this node

child_labels

List of labels for children of this node



182
183
184
185
186
# File 'lib/treebank.rb', line 182

def initialize(label = nil, child_labels = [])
  @label = label
  @children = []
  child_labels.each {|label| create_child!(label)}
end

Instance Attribute Details

#childrenObject (readonly)

The children of this node.



173
174
175
# File 'lib/treebank.rb', line 173

def children
  @children
end

#labelObject

This node’s label



176
177
178
# File 'lib/treebank.rb', line 176

def label
  @label
end

Class Method Details

.from_s(s, left = '(', right = ')') ⇒ Object

Read the tree from a bracketed string.

s

Bracketed string

left

Left bracket symbol

right

Right bracket symbol

This function uses a Treebank::Parser object to create the tree from s.



196
197
198
199
200
# File 'lib/treebank.rb', line 196

def Node.from_s(s, left = '(', right = ')')
  nodes = Parser.new(TokenStream.new(s, left, right), self).collect
  raise "#{s} defines multiple trees" if nodes.length != 1
  nodes.first
end

Instance Method Details

#==(other) ⇒ Object

If the other object is a tree and every node label in the corresponding nodes of the two depth first enumerations match, the trees are equivalent.



257
258
259
260
261
262
263
264
265
266
267
# File 'lib/treebank.rb', line 257

def ==(other)
  return false if not other.kind_of? self.class
  return true if self.empty? and other.empty?
  self_enum = Enumerable::Enumerator.new(self, :each_depth_first)
  other_enum = Enumerable::Enumerator.new(other, :each_depth_first)
  mismatch = self_enum.zip(other_enum).find \
  {|self_node, other_node| self_node.nil? or \
    other_node.nil? or \
    self_node.label != other_node.label}
  mismatch.nil?
end

#[](*index) ⇒ Object

Return the child node specified by the coordinate index or nil if the coordinate is out of range. An empty argument list returns this node.

index

A list of integers that indexes the child node

t = Treebank::Node.from_s("(A (B b) (C (D d) (E e)))")
<Treebank::Node A [B C]>
t[1,0]
<Treebank::Node D [d]>


342
343
344
345
346
347
348
349
# File 'lib/treebank.rb', line 342

def [](*index)
  child = self
  index.each do |i|
    child = child.children[i]
    break if child.nil?
  end
  child
end

#attach_child!(node, index = nil) ⇒ Object

Attach an existing node as the child of this node.

node

The node to add. It must be the same type as this node.

index

Optional insertion index. If unspecified, the node is added to the end of the child list.

This function returns the added Node object.



287
288
289
290
291
292
293
294
295
# File 'lib/treebank.rb', line 287

def attach_child!(node, index = nil)
  raise "#{node} is not class #{self.class}" if node.class != self.class
  if index.nil?
    @children << node
  else
    @children[index, 0] = node
  end
  node
end

#breadth_first_enumerator(indexed = false, visit = nil) ⇒ Object

Return an Enumerator object that enumerates this node and its descendants breadth-first.

See the each_descendant documentation for more details on the function arguments.



415
416
417
# File 'lib/treebank.rb', line 415

def breadth_first_enumerator(indexed = false, visit = nil)
  Enumerable::Enumerator.new(self, :each_breadth_first, indexed, visit)
end

#create_child!(label, index = nil) ⇒ Object

Create a new node and add it as a child of this node.

label

The label of a node to create

index

Optional insertion index. If unspecified, the node is added to the end of the child list.

This function returns the added Node object.



276
277
278
# File 'lib/treebank.rb', line 276

def create_child!(label, index = nil)
  attach_child!(self.class.new(label), index)
end

#depth_first_enumerator(indexed = false, visit = nil) ⇒ Object

Return an Enumerator object that enumerates this node and its descendants depth-first.

See the each_descendant documentation for more details on the function arguments.



381
382
383
# File 'lib/treebank.rb', line 381

def depth_first_enumerator(indexed = false, visit = nil)
  Enumerable::Enumerator.new(self, :each_depth_first, indexed, visit)
end

#detach_child!(node) ⇒ Object

Removes the specfied node from this node’s child list.

node

The node to detach



300
301
302
# File 'lib/treebank.rb', line 300

def detach_child!(node)
  raise "#{node} is not a child of #{self}" if @children.delete(node).nil?
end

#eachObject

Enumerate the children of this node.



305
306
307
# File 'lib/treebank.rb', line 305

def each
  @children.each {|node| yield node}
end

#each_breadth_first(indexed = false, visit = nil) ⇒ Object

Enumerate this node and its children breadth-first.

indexed

Return indexes along with nodes?

visit

Optional enumeration control procedure

> t = Treebank::Node.from_s("(A (B b) (C c))")
> t.each_breadth_first() {|n,index| puts n.label}
A
B
C
b
c
> t.each_breadth_first(true) {|n,index| puts "#{n.label} #{index.inspect}"}
A []
B [0]
C [1]
b [0, 0]
c [1, 0]

See the each_descendant documentation for more details on the function arguments.



406
407
408
# File 'lib/treebank.rb', line 406

def each_breadth_first(indexed = false, visit = nil)
  each_descendant(indexed, :breadth_first, visit) {|node| yield node}
end

#each_depth_first(indexed = false, visit = nil) ⇒ Object

Enumerate this node and its children depth-first.

indexed

Return indexes along with nodes?

visit

Optional enumeration control procedure

> t = Treebank::Node.from_s("(A (B b) (C c))")
> t.each_depth_first() {|n,index| puts n.label}
A
B
b
C
c
> t.each_depth_first(true) {|n,index| puts "#{n.label} #{index.inspect}"}
A []
B [0]
b [0, 0]
C [1]
c [1, 0]

See the each_descendant documentation for more details on the function arguments.



372
373
374
# File 'lib/treebank.rb', line 372

def each_depth_first(indexed = false, visit = nil)
  each_descendant(indexed, :depth_first, visit) {|node| yield node}
end

#empty?Boolean

An empty node has no label and no children.

Returns:

  • (Boolean)


315
316
317
# File 'lib/treebank.rb', line 315

def empty?
  @label.nil? and @children.empty?
end

#inspectObject

Show this node’s label and the labels of its children.



249
250
251
252
# File 'lib/treebank.rb', line 249

def inspect
  child_labels = @children.collect {|n| n.label}
  "<#{self.class} #{@label} [#{child_labels.join(' ')}]>"
end

#leaf?Boolean

A leaf node has no children.

Returns:

  • (Boolean)


310
311
312
# File 'lib/treebank.rb', line 310

def leaf?
  @children.empty?
end

#leaves(&block) ⇒ Object

Return all the leaf nodes beneath this node.

block

An optional block to run on each leaf



327
328
329
330
331
# File 'lib/treebank.rb', line 327

def leaves(&block)
  leaves = depth_first_enumerator.find_all {|node| node.leaf?}
  leaves = leaves.collect {|leaf| block.call(leaf)} if not block.nil?
  leaves
end

#preterminal?Boolean

A preterminal node dominates a single leaf node.

Returns:

  • (Boolean)


320
321
322
# File 'lib/treebank.rb', line 320

def preterminal?
  @children.length == 1 and @children.first.leaf?
end

#to_s(multiline = true) ⇒ Object

This writes to a bracketed string representation that can be read by the Parser object.

multiline

The string representation is in indented multiline format if this is true and on a single line if it is false.



207
208
209
210
211
212
213
214
# File 'lib/treebank.rb', line 207

def to_s(multiline = true)
  if multiline
    multiline_to_s(0, nil, nil)
  else
    "(#{label} #{preterminal? ? @children.first.label :
                                @children.join(' ')})"
  end
end