bracket_notation 1.0.5 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|