bracket_notation 1.0.5 → 1.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +8 -0
- data/Manifest +17 -1
- data/README.rdoc +31 -7
- data/Rakefile +2 -1
- data/bracket_notation.gemspec +9 -6
- data/init.rb +1 -1
- data/lib/bracket_notation.rb +3 -1
- data/lib/bracket_notation/evaluator.rb +2 -1
- data/lib/bracket_notation/expressions.rb +1 -1
- data/lib/bracket_notation/expressions/expression.rb +1 -1
- data/lib/bracket_notation/expressions/identifier.rb +1 -1
- data/lib/bracket_notation/expressions/terminal.rb +1 -1
- data/lib/bracket_notation/geometry.rb +31 -0
- data/lib/bracket_notation/geometry/point.rb +69 -0
- data/lib/bracket_notation/geometry/rect.rb +64 -0
- data/lib/bracket_notation/geometry/size.rb +69 -0
- data/lib/bracket_notation/parser.rb +1 -1
- data/lib/bracket_notation/scanner.rb +1 -1
- data/lib/bracket_notation/token.rb +1 -1
- data/lib/bracket_notation/version.rb +3 -3
- data/lib/bracket_notation/views.rb +33 -0
- data/lib/bracket_notation/views/branch.rb +40 -0
- data/lib/bracket_notation/views/leaf.rb +34 -0
- data/lib/bracket_notation/views/node.rb +152 -0
- data/lib/bracket_notation/views/tree.rb +181 -0
- data/test/functional/evaluator_test.rb +1 -1
- data/test/functional/node_test.rb +132 -0
- data/test/functional/parser_test.rb +1 -1
- data/test/functional/scanner_test.rb +1 -1
- data/test/functional/tree_test.rb +67 -0
- data/test/integration/layout_test.rb +151 -0
- data/test/integration/parsing_test.rb +1 -1
- data/test/test_helper.rb +1 -1
- data/test/unit/expression_test.rb +1 -1
- data/test/unit/point_test.rb +69 -0
- data/test/unit/rect_test.rb +58 -0
- data/test/unit/size_test.rb +69 -0
- data/test/unit/token_test.rb +1 -1
- metadata +48 -7
@@ -23,7 +23,7 @@
|
|
23
23
|
# and small portions of his code have been incorporated in the parser.
|
24
24
|
#
|
25
25
|
# Author:: Cody Brimhall (mailto:brimhall@somuchwit.com)
|
26
|
-
# Copyright:: Copyright (c) 2010 Cody Brimhall
|
26
|
+
# Copyright:: Copyright (c) 2010-2011 Cody Brimhall
|
27
27
|
# License:: Distributed under the terms of the GNU General Public License, v. 3
|
28
28
|
|
29
29
|
module BracketNotation # :nodoc:
|
@@ -23,7 +23,7 @@
|
|
23
23
|
# and small portions of his code have been incorporated in the parser.
|
24
24
|
#
|
25
25
|
# Author:: Cody Brimhall (mailto:brimhall@somuchwit.com)
|
26
|
-
# Copyright:: Copyright (c) 2010 Cody Brimhall
|
26
|
+
# Copyright:: Copyright (c) 2010-2011 Cody Brimhall
|
27
27
|
# License:: Distributed under the terms of the GNU General Public License, v. 3
|
28
28
|
|
29
29
|
module BracketNotation # :nodoc:
|
@@ -23,7 +23,7 @@
|
|
23
23
|
# and small portions of his code have been incorporated in the parser.
|
24
24
|
#
|
25
25
|
# Author:: Cody Brimhall (mailto:brimhall@somuchwit.com)
|
26
|
-
# Copyright:: Copyright (c) 2010 Cody Brimhall
|
26
|
+
# Copyright:: Copyright (c) 2010-2011 Cody Brimhall
|
27
27
|
# License:: Distributed under the terms of the GNU General Public License, v. 3
|
28
28
|
|
29
29
|
module BracketNotation # :nodoc:
|
@@ -23,14 +23,14 @@
|
|
23
23
|
# and small portions of his code have been incorporated in the parser.
|
24
24
|
#
|
25
25
|
# Author:: Cody Brimhall (mailto:brimhall@somuchwit.com)
|
26
|
-
# Copyright:: Copyright (c) 2010 Cody Brimhall
|
26
|
+
# Copyright:: Copyright (c) 2010-2011 Cody Brimhall
|
27
27
|
# License:: Distributed under the terms of the GNU General Public License, v. 3
|
28
28
|
|
29
29
|
module BracketNotation # :nodoc:
|
30
30
|
module Version # :nodoc:
|
31
31
|
MAJOR = 1
|
32
|
-
MINOR =
|
33
|
-
MAINT =
|
32
|
+
MINOR = 1
|
33
|
+
MAINT = 0
|
34
34
|
|
35
35
|
# Returns the current version string.
|
36
36
|
def self.to_s;
|
@@ -0,0 +1,33 @@
|
|
1
|
+
#--
|
2
|
+
# This file is part of BracketNotation.
|
3
|
+
#
|
4
|
+
# BracketNotation is free software: you can redistribute it and/or modify
|
5
|
+
# it under the terms of the GNU General Public License as published by
|
6
|
+
# the Free Software Foundation, either version 3 of the License, or
|
7
|
+
# (at your option) any later version.
|
8
|
+
#
|
9
|
+
# BracketNotation is distributed in the hope that it will be useful,
|
10
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
11
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
12
|
+
# GNU General Public License for more details.
|
13
|
+
#
|
14
|
+
# You should have received a copy of the GNU General Public License
|
15
|
+
# along with BracketNotation. If not, see <http://www.gnu.org/licenses/>.
|
16
|
+
#++
|
17
|
+
# BracketNotation is a parser for generating syntax trees from sentences
|
18
|
+
# annotated with the kind of bracket notation that is commonly used by
|
19
|
+
# linguists. The result is a tree structure with nodes that describe the phrases
|
20
|
+
# and constituents of the sentence.
|
21
|
+
#
|
22
|
+
# BracketNotation was inspired by Yoichiro Hasebe's RSyntaxTree[http://yohasebe.com/rsyntaxtree/],
|
23
|
+
# and small portions of his code have been incorporated in the parser.
|
24
|
+
#
|
25
|
+
# Author:: Cody Brimhall (mailto:brimhall@somuchwit.com)
|
26
|
+
# Copyright:: Copyright (c) 2010-2011 Cody Brimhall
|
27
|
+
# License:: Distributed under the terms of the GNU General Public License, v. 3
|
28
|
+
|
29
|
+
require 'rmagick'
|
30
|
+
require 'bracket_notation/views/node'
|
31
|
+
require 'bracket_notation/views/branch'
|
32
|
+
require 'bracket_notation/views/leaf'
|
33
|
+
require 'bracket_notation/views/tree'
|
@@ -0,0 +1,40 @@
|
|
1
|
+
#--
|
2
|
+
# This file is part of BracketNotation.
|
3
|
+
#
|
4
|
+
# BracketNotation is free software: you can redistribute it and/or modify
|
5
|
+
# it under the terms of the GNU General Public License as published by
|
6
|
+
# the Free Software Foundation, either version 3 of the License, or
|
7
|
+
# (at your option) any later version.
|
8
|
+
#
|
9
|
+
# BracketNotation is distributed in the hope that it will be useful,
|
10
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
11
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
12
|
+
# GNU General Public License for more details.
|
13
|
+
#
|
14
|
+
# You should have received a copy of the GNU General Public License
|
15
|
+
# along with BracketNotation. If not, see <http://www.gnu.org/licenses/>.
|
16
|
+
#++
|
17
|
+
# BracketNotation is a parser for generating syntax trees from sentences
|
18
|
+
# annotated with the kind of bracket notation that is commonly used by
|
19
|
+
# linguists. The result is a tree structure with nodes that describe the phrases
|
20
|
+
# and constituents of the sentence.
|
21
|
+
#
|
22
|
+
# BracketNotation was inspired by Yoichiro Hasebe's RSyntaxTree[http://yohasebe.com/rsyntaxtree/],
|
23
|
+
# and small portions of his code have been incorporated in the parser.
|
24
|
+
#
|
25
|
+
# Author:: Cody Brimhall (mailto:brimhall@somuchwit.com)
|
26
|
+
# Copyright:: Copyright (c) 2010-2011 Cody Brimhall
|
27
|
+
# License:: Distributed under the terms of the GNU General Public License, v. 3
|
28
|
+
|
29
|
+
module BracketNotation # :nodoc:
|
30
|
+
module View # :nodoc:
|
31
|
+
class Branch < Node
|
32
|
+
attr_accessor :roll_up
|
33
|
+
|
34
|
+
def initialize(tree, content)
|
35
|
+
super
|
36
|
+
@roll_up = false
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
#--
|
2
|
+
# This file is part of BracketNotation.
|
3
|
+
#
|
4
|
+
# BracketNotation is free software: you can redistribute it and/or modify
|
5
|
+
# it under the terms of the GNU General Public License as published by
|
6
|
+
# the Free Software Foundation, either version 3 of the License, or
|
7
|
+
# (at your option) any later version.
|
8
|
+
#
|
9
|
+
# BracketNotation is distributed in the hope that it will be useful,
|
10
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
11
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
12
|
+
# GNU General Public License for more details.
|
13
|
+
#
|
14
|
+
# You should have received a copy of the GNU General Public License
|
15
|
+
# along with BracketNotation. If not, see <http://www.gnu.org/licenses/>.
|
16
|
+
#++
|
17
|
+
# BracketNotation is a parser for generating syntax trees from sentences
|
18
|
+
# annotated with the kind of bracket notation that is commonly used by
|
19
|
+
# linguists. The result is a tree structure with nodes that describe the phrases
|
20
|
+
# and constituents of the sentence.
|
21
|
+
#
|
22
|
+
# BracketNotation was inspired by Yoichiro Hasebe's RSyntaxTree[http://yohasebe.com/rsyntaxtree/],
|
23
|
+
# and small portions of his code have been incorporated in the parser.
|
24
|
+
#
|
25
|
+
# Author:: Cody Brimhall (mailto:brimhall@somuchwit.com)
|
26
|
+
# Copyright:: Copyright (c) 2010-2011 Cody Brimhall
|
27
|
+
# License:: Distributed under the terms of the GNU General Public License, v. 3
|
28
|
+
|
29
|
+
module BracketNotation # :nodoc:
|
30
|
+
module View # :nodoc:
|
31
|
+
class Leaf < Node
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,152 @@
|
|
1
|
+
#--
|
2
|
+
# This file is part of BracketNotation.
|
3
|
+
#
|
4
|
+
# BracketNotation is free software: you can redistribute it and/or modify
|
5
|
+
# it under the terms of the GNU General Public License as published by
|
6
|
+
# the Free Software Foundation, either version 3 of the License, or
|
7
|
+
# (at your option) any later version.
|
8
|
+
#
|
9
|
+
# BracketNotation is distributed in the hope that it will be useful,
|
10
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
11
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
12
|
+
# GNU General Public License for more details.
|
13
|
+
#
|
14
|
+
# You should have received a copy of the GNU General Public License
|
15
|
+
# along with BracketNotation. If not, see <http://www.gnu.org/licenses/>.
|
16
|
+
#++
|
17
|
+
# BracketNotation is a parser for generating syntax trees from sentences
|
18
|
+
# annotated with the kind of bracket notation that is commonly used by
|
19
|
+
# linguists. The result is a tree structure with nodes that describe the phrases
|
20
|
+
# and constituents of the sentence.
|
21
|
+
#
|
22
|
+
# BracketNotation was inspired by Yoichiro Hasebe's RSyntaxTree[http://yohasebe.com/rsyntaxtree/],
|
23
|
+
# and small portions of his code have been incorporated in the parser.
|
24
|
+
#
|
25
|
+
# Author:: Cody Brimhall (mailto:brimhall@somuchwit.com)
|
26
|
+
# Copyright:: Copyright (c) 2010-2011 Cody Brimhall
|
27
|
+
# License:: Distributed under the terms of the GNU General Public License, v. 3
|
28
|
+
|
29
|
+
require 'bracket_notation/geometry'
|
30
|
+
|
31
|
+
module BracketNotation # :nodoc:
|
32
|
+
module View # :nodoc:
|
33
|
+
class Node
|
34
|
+
attr_accessor :tree, :content, :parent, :children, :rect, :align_to_grid
|
35
|
+
|
36
|
+
def initialize(tree, content)
|
37
|
+
@tree = tree
|
38
|
+
@content = content
|
39
|
+
@parent = nil
|
40
|
+
@children = []
|
41
|
+
@rect = BracketNotation::Geometry::Rect.new
|
42
|
+
@align_to_grid = true
|
43
|
+
end
|
44
|
+
|
45
|
+
# Custom setter for the node rect. If @align_to_grid is true, rect co-
|
46
|
+
# ordinates and dimensions will be rounded to the nearest integer.
|
47
|
+
def rect=(rvalue)
|
48
|
+
return if @rect == rvalue
|
49
|
+
|
50
|
+
@rect = if @align_to_grid
|
51
|
+
adjusted_origin = BracketNotation::Geometry::Point.new(rvalue.origin.x.round, rvalue.origin.y.round)
|
52
|
+
adjusted_size = BracketNotation::Geometry::Size.new(rvalue.size.width.round, rvalue.size.height.round)
|
53
|
+
BracketNotation::Geometry::Rect.new(adjusted_origin, adjusted_size)
|
54
|
+
else
|
55
|
+
rvalue
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
# Return the node's left sibling, or nil if the node is the leftmost child of
|
60
|
+
# its parent.
|
61
|
+
def left_sibling
|
62
|
+
return nil if @parent.nil?
|
63
|
+
|
64
|
+
left_sibling = nil
|
65
|
+
self_index = @parent.children.index(self)
|
66
|
+
left_sibling = @parent.children[self_index - 1] if self_index > 0
|
67
|
+
|
68
|
+
return left_sibling
|
69
|
+
end
|
70
|
+
|
71
|
+
# Return the node's right sibling, or nil if the node is the rightmost child
|
72
|
+
# of its parent.
|
73
|
+
def right_sibling
|
74
|
+
return nil if @parent.nil?
|
75
|
+
|
76
|
+
self_index = @parent.children.index(self)
|
77
|
+
right_sibling = @parent.children[self_index + 1]
|
78
|
+
|
79
|
+
return right_sibling
|
80
|
+
end
|
81
|
+
|
82
|
+
# Return the list of nodes leading from the current node to the tree root,
|
83
|
+
# starting with the current node's parent.
|
84
|
+
def ancestors
|
85
|
+
node_list = []
|
86
|
+
next_up = self
|
87
|
+
node_list << next_up while next_up = next_up.parent
|
88
|
+
|
89
|
+
return node_list
|
90
|
+
end
|
91
|
+
|
92
|
+
# Return the dimensions of the rect that contains the nod and all of its
|
93
|
+
# descendants
|
94
|
+
def subtree_size
|
95
|
+
return @rect.size if kind_of? Leaf or @children.count == 0
|
96
|
+
|
97
|
+
new_subtree_size = BracketNotation::Geometry::Size.new(0, @rect.size.height)
|
98
|
+
subtree_widths = []
|
99
|
+
subtree_heights = []
|
100
|
+
|
101
|
+
@children.each do |child|
|
102
|
+
child_subtree_size = child.subtree_size
|
103
|
+
new_subtree_size = new_subtree_size.size_by_adding_to_width(child_subtree_size.width)
|
104
|
+
subtree_heights << child_subtree_size.height
|
105
|
+
end
|
106
|
+
|
107
|
+
new_subtree_size = new_subtree_size.size_by_adding_to_width_and_height(@tree.node_h_margin * (children.count - 1), @tree.node_v_margin + subtree_heights.sort.last)
|
108
|
+
return BracketNotation::Geometry::Size.new(@rect.size.width > new_subtree_size.width ? @rect.size.width : new_subtree_size.width, new_subtree_size.height)
|
109
|
+
end
|
110
|
+
|
111
|
+
# Return the coordinates of the node's top left corner.
|
112
|
+
def corner_top_left
|
113
|
+
@rect.origin
|
114
|
+
end
|
115
|
+
|
116
|
+
# Return the coordinates of the node's top right corner.
|
117
|
+
def corner_top_right
|
118
|
+
BracketNotation::Geometry::Point.new(@rect.origin.x + @rect.size.width, @rect.origin.y)
|
119
|
+
end
|
120
|
+
|
121
|
+
# Return the coordinates of the node's bottom right corner.
|
122
|
+
def corner_bottom_right
|
123
|
+
BracketNotation::Geometry::Point.new(@rect.origin.x + @rect.size.width, @rect.origin.y + @rect.size.height)
|
124
|
+
end
|
125
|
+
|
126
|
+
# Return the coordinates of the node's bottom left corner.
|
127
|
+
def corner_bottom_left
|
128
|
+
BracketNotation::Geometry::Point.new(@rect.origin.x, @rect.origin.y + @rect.size.height)
|
129
|
+
end
|
130
|
+
|
131
|
+
# Return the coordinates of the middle of the node's top side.
|
132
|
+
def side_middle_top
|
133
|
+
BracketNotation::Geometry::Point.new(@rect.origin.x + (@rect.size.width / 2), @rect.origin.y)
|
134
|
+
end
|
135
|
+
|
136
|
+
# Return the coordinates of the middle of the node's right side.
|
137
|
+
def side_middle_right
|
138
|
+
BracketNotation::Geometry::Point.new(@rect.origin.x + @rect.size.width, @rect.origin.y + (@rect.size.height / 2))
|
139
|
+
end
|
140
|
+
|
141
|
+
# Return the coordinates of the middle of the node's bottom side.
|
142
|
+
def side_middle_bottom
|
143
|
+
BracketNotation::Geometry::Point.new(@rect.origin.x + (@rect.size.width / 2), @rect.origin.y + @rect.size.height)
|
144
|
+
end
|
145
|
+
|
146
|
+
# Return the coordinates of the middle of the node's left side.
|
147
|
+
def side_middle_left
|
148
|
+
BracketNotation::Geometry::Point.new(@rect.origin.x, @rect.origin.y + (@rect.size.height / 2))
|
149
|
+
end
|
150
|
+
end
|
151
|
+
end
|
152
|
+
end
|
@@ -0,0 +1,181 @@
|
|
1
|
+
#--
|
2
|
+
# This file is part of BracketNotation.
|
3
|
+
#
|
4
|
+
# BracketNotation is free software: you can redistribute it and/or modify
|
5
|
+
# it under the terms of the GNU General Public License as published by
|
6
|
+
# the Free Software Foundation, either version 3 of the License, or
|
7
|
+
# (at your option) any later version.
|
8
|
+
#
|
9
|
+
# BracketNotation is distributed in the hope that it will be useful,
|
10
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
11
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
12
|
+
# GNU General Public License for more details.
|
13
|
+
#
|
14
|
+
# You should have received a copy of the GNU General Public License
|
15
|
+
# along with BracketNotation. If not, see <http://www.gnu.org/licenses/>.
|
16
|
+
#++
|
17
|
+
# BracketNotation is a parser for generating syntax trees from sentences
|
18
|
+
# annotated with the kind of bracket notation that is commonly used by
|
19
|
+
# linguists. The result is a tree structure with nodes that describe the phrases
|
20
|
+
# and constituents of the sentence.
|
21
|
+
#
|
22
|
+
# BracketNotation was inspired by Yoichiro Hasebe's RSyntaxTree[http://yohasebe.com/rsyntaxtree/],
|
23
|
+
# and small portions of his code have been incorporated in the parser.
|
24
|
+
#
|
25
|
+
# Author:: Cody Brimhall (mailto:brimhall@somuchwit.com)
|
26
|
+
# Copyright:: Copyright (c) 2010-2011 Cody Brimhall
|
27
|
+
# License:: Distributed under the terms of the GNU General Public License, v. 3
|
28
|
+
|
29
|
+
module BracketNotation # :nodoc:
|
30
|
+
module View # :nodoc:
|
31
|
+
class Tree
|
32
|
+
attr_accessor :input, :root, :font_name, :font_point_size, :tree_padding, :node_h_margin, :node_v_margin, :node_padding, :color_bg, :color_fg, :color_line, :color_branch, :color_leaf
|
33
|
+
|
34
|
+
# Throws :prune, which is caught by #traverse, signaling that method to cease
|
35
|
+
# visiting nodes on the current branch.
|
36
|
+
def self.prune
|
37
|
+
throw(:prune)
|
38
|
+
end
|
39
|
+
|
40
|
+
def initialize(input)
|
41
|
+
@input = input
|
42
|
+
@font_name = "Helvetica"
|
43
|
+
@font_point_size = 40
|
44
|
+
@tree_padding = 20
|
45
|
+
@node_h_margin = 50
|
46
|
+
@node_v_margin = 30
|
47
|
+
@node_padding = 10
|
48
|
+
@color_bg = "white"
|
49
|
+
@color_fg = "black"
|
50
|
+
@color_line = "red"
|
51
|
+
@color_branch = "blue"
|
52
|
+
@color_leaf = "green"
|
53
|
+
end
|
54
|
+
|
55
|
+
# Traverse the tree, passing each visited node and the current depth to the
|
56
|
+
# given block.
|
57
|
+
#
|
58
|
+
# Options are:
|
59
|
+
# * <tt>:depth</tt> - The starting value of the depth counter. The default is
|
60
|
+
# +0+.
|
61
|
+
# * <tt>:order</tt> - The traversal order to follow. Allowed values are:
|
62
|
+
# +:preorder+ (or +:pre+), +:postorder+ (or +:post+), +:breadthfirst+ (or
|
63
|
+
# +:breadth+). The default is +:preorder+.
|
64
|
+
# * <tt>:root</tt> - The root node of the subtree to be traversed. The default
|
65
|
+
# is the root node of the entire tree.
|
66
|
+
#
|
67
|
+
def traverse(options = {}, &block)
|
68
|
+
options[:order] ||= :preorder
|
69
|
+
options[:depth] ||= 0
|
70
|
+
options[:root] ||= @root
|
71
|
+
|
72
|
+
return if @root.nil?
|
73
|
+
|
74
|
+
if [:breadth, :breadthfirst].include? options[:order]
|
75
|
+
node_queue = [options[:root]]
|
76
|
+
|
77
|
+
while node = node_queue.shift
|
78
|
+
yield node, node.ancestors.length
|
79
|
+
node_queue += node.children
|
80
|
+
end
|
81
|
+
else
|
82
|
+
catch(:prune) do
|
83
|
+
case options[:order]
|
84
|
+
when :pre, :preorder
|
85
|
+
yield options[:root], options[:depth]
|
86
|
+
options[:root].children.each {|child| traverse({:order => :pre, :root => child, :depth => options[:depth] + 1}, &block) }
|
87
|
+
when :post, :postorder
|
88
|
+
options[:root].children.each {|child| traverse({:order => :post, :root => child, :depth => options[:depth] + 1}, &block) }
|
89
|
+
yield options[:root], options[:depth]
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
# Computes the node tree layout, setting the correct origin and dimensions
|
96
|
+
# for each node.
|
97
|
+
def compute_layout
|
98
|
+
layout_nodes
|
99
|
+
|
100
|
+
old_root_origin_x = @root.rect.origin.x
|
101
|
+
new_root_origin_x = ((@root.subtree_size.width + (@tree_padding * 2)) / 2) - (@root.rect.size.width / 2)
|
102
|
+
delta = new_root_origin_x - old_root_origin_x
|
103
|
+
|
104
|
+
traverse {|node, depth| node.rect = BracketNotation::Geometry::Rect.new(node.rect.origin.point_by_adding_to_x(delta), node.rect.size) }
|
105
|
+
end
|
106
|
+
|
107
|
+
def inspect
|
108
|
+
leaf_content = []
|
109
|
+
traverse {|node, depth| leaf_content << node.content if node.kind_of? Leaf }
|
110
|
+
return "#{@input} >> \"#{leaf_content.join(" ")}\""
|
111
|
+
end
|
112
|
+
|
113
|
+
alias :to_s :inspect
|
114
|
+
|
115
|
+
def pretty_print
|
116
|
+
traverse do |node, depth|
|
117
|
+
depth.times { print "--" }
|
118
|
+
print " " if depth > 0
|
119
|
+
puts node.to_s
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
private
|
124
|
+
|
125
|
+
# Walks the node tree, setting origins and dimensions
|
126
|
+
def layout_nodes(node = @root, depth = 0)
|
127
|
+
compute_node_dimensions(node)
|
128
|
+
compute_node_origin_y(node)
|
129
|
+
|
130
|
+
node.children.each {|child| layout_nodes(child, depth + 1) }
|
131
|
+
|
132
|
+
compute_subtree_origin_x(node)
|
133
|
+
end
|
134
|
+
|
135
|
+
def compute_node_dimensions(node)
|
136
|
+
background = Magick::Image.new(500, 250)
|
137
|
+
gc = Magick::Draw.new
|
138
|
+
font = @font_name
|
139
|
+
pointsize = @font_point_size
|
140
|
+
|
141
|
+
# Write the node content in a scratch image to calculate the text metrics
|
142
|
+
gc.annotate(background, 0, 0, 0, 0, node.content) do |gc|
|
143
|
+
gc.font = font
|
144
|
+
gc.pointsize = pointsize
|
145
|
+
gc.gravity = Magick::CenterGravity
|
146
|
+
gc.stroke = "none"
|
147
|
+
end
|
148
|
+
|
149
|
+
metrics = gc.get_type_metrics(background, node.content)
|
150
|
+
node.rect = BracketNotation::Geometry::Rect.new(node.rect.origin, BracketNotation::Geometry::Size.new(metrics.width, @font_point_size + (@node_padding * 2)))
|
151
|
+
end
|
152
|
+
|
153
|
+
def compute_node_origin_y(node)
|
154
|
+
adjusted_origin_y = node.parent.nil? ? @tree_padding : node.parent.rect.origin.y + node.parent.rect.size.height + @node_v_margin
|
155
|
+
new_origin = BracketNotation::Geometry::Point.new(node.rect.origin.x, adjusted_origin_y)
|
156
|
+
node.rect = BracketNotation::Geometry::Rect.new(BracketNotation::Geometry::Point.new(node.rect.origin.x, adjusted_origin_y), node.rect.size)
|
157
|
+
end
|
158
|
+
|
159
|
+
def compute_subtree_origin_x(node)
|
160
|
+
return if node.kind_of? Leaf or node.children.count == 0
|
161
|
+
|
162
|
+
node_middle = node.side_middle_top.x
|
163
|
+
children_subtree_widths = node.children.collect {|child| child.subtree_size.width}
|
164
|
+
max_subtree_width = children_subtree_widths.sort.last
|
165
|
+
subtree_width = (max_subtree_width * children_subtree_widths.count) + (@node_h_margin * (node.children.count - 1))
|
166
|
+
subtree_origin_x = node_middle - (subtree_width / 2)
|
167
|
+
|
168
|
+
node.children.each do |child|
|
169
|
+
child_subtree_width = max_subtree_width
|
170
|
+
child_node_middle = child.side_middle_top.x
|
171
|
+
old_subtree_origin_x = child_node_middle - (child_subtree_width / 2)
|
172
|
+
delta = subtree_origin_x - old_subtree_origin_x
|
173
|
+
|
174
|
+
traverse(:root => child) {|node, depth| node.rect = BracketNotation::Geometry::Rect.new(node.rect.origin.point_by_adding_to_x(delta), node.rect.size) }
|
175
|
+
|
176
|
+
subtree_origin_x += max_subtree_width + @node_h_margin
|
177
|
+
end
|
178
|
+
end
|
179
|
+
end
|
180
|
+
end
|
181
|
+
end
|