Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Make edge following more strict

When following edges we keep track of what edge characters are allowed
next. These prevents following edges such as:

o--o--o
     /
     \
      o

And fixes a bug where, when trying to find parent nodes for B, we'd
traverse from B to \ to A in situations like this:

A B
 \

The edge-traversing algorithm is now much more data-driven. We use a
hash that describes what to do next for each type of edge character, as
well as what to do at the very start of the search.

This changed the sort order of parent nodes in some situations. We
should probably apply some overall sort to the parent nodes so they
aren't so sensitive to the traversal algorithm.

Fixes #5. Also improves #7 slightly, because there are no longer arrows
pointing from numbered labels to nodes. There are still circles around
the numbered labels though.
  • Loading branch information...
commit b56cebc6ae3529e5fa6a8e1e821a6071f84b7d24 1 parent 7c1ff80
@aroben authored
Showing with 64 additions and 19 deletions.
  1. +40 −18 lib/asciidag.rb
  2. +24 −1 test/parser_test.rb
View
58 lib/asciidag.rb
@@ -90,17 +90,44 @@ def self.find_and_remove_arrowed_branch_label(line, y)
end
def self.find_parents(position, nodes_by_position, lines)
- positions_to_search = lambda do |position|
- x = position[0] - 1
- below = position[1] - 1
- above = position[1] + 1
- (below..above).collect { |y| [x, y] }.reject do |(x, y)|
- x < 0 || y < 0
- end
+ # This is a hash that maps edge characters to options for where to search
+ # next to follow the edge. Each option consists of an array that contains
+ # two elements: a position delta (represented as a sub-array containing
+ # separate X and Y deltas), and a set of valid edge characters that could
+ # be found after applying the position delta. The special :initial entry
+ # represents what to do on the first step of the algorithm.
+ next_steps = {
+ '-' => [
+ [[-1, 0], '-'],
+ ],
+ '\\' => [
+ [[-1, 1], '-\\|'],
+ ],
+ '|' => [
+ [[0, 1], '|'],
+ ],
+ '/' => [
+ [[-1, -1], '/-'],
+ ],
+ :initial => [
+ [[-1, 1], '\\'],
+ [[-1, 0], '-'],
+ [[-1, -1], '/'],
+ ],
+ }
+
+ inner = nil
+ continue_search = lambda do |current_character, position|
+ x, y = position
+ next_steps[current_character].collect do |d, cs|
+ dx, dy = d
+ inner.call [x + dx, y + dy], cs
+ end.reject { |p| p.nil? }
end
- inner = lambda do |position|
+ inner = lambda do |position, valid_edge_characters|
x, y = position
+ return unless x >= 0 && y >= 0
parent = nodes_by_position[[x, y]]
return parent unless parent.nil?
line = lines[y]
@@ -108,22 +135,17 @@ def self.find_parents(position, nodes_by_position, lines)
ord = line[x]
return if ord.nil?
case ord.chr
- when '-'
- inner.call [x - 1, y]
- when '\\'
- inner.call [x - 1, y + 1]
- when '|'
- inner.call [x, y + 1]
- when '/'
- inner.call [x - 1, y - 1]
+ when /[-\/\\|]/
+ return unless valid_edge_characters.chars.include?(ord.chr)
+ continue_search.call ord.chr, position
when NODE_REGEXP
# This might be part of a multi-character node label.
start_x = line.rindex(/[\s\-\/\\|]/, x)
return if start_x.nil?
- inner.call [start_x + 1, y]
+ inner.call [start_x + 1, y], ''
end
end
- positions_to_search.call(position).collect { |p| inner.call p }.reject { |p| p.nil? }
+ continue_search.call(:initial, position).flatten
end
NODE_REGEXP = /[^\s\-\/\\|]+/
View
25 test/parser_test.rb
@@ -49,6 +49,16 @@
\\ \\
t--t--t--m <-- their branch:
EOF
+
+ @graph8 = AsciiDag.parse <<-EOF
+G-Y-G-W-W-W-X-X-X-X
+ \\ /
+ W-W-B
+ /
+Y---G-W---W
+ \\ / \\
+Y-Y X-X-X-X
+EOF
end
test 'parses nodes' do
@@ -105,7 +115,7 @@
c = find_node @graph4, 'C'
g = find_node @graph4, 'G'
h = find_node @graph4, 'H'
- assert_equal [g, c], h.parents
+ assert_equal [c, g], h.parents
end
test 'nodes get unique IDs' do
@@ -154,4 +164,17 @@
a = find_node @graph2, "A'"
assert_equal "A&#8242;", a.dot_label
end
+
+ test 'should only follow edges in allowed directions' do
+ xs = find_all_nodes @graph8, 'X'
+ ws = find_all_nodes @graph8, 'W'
+
+ x = xs[4]
+ w = ws[6]
+ assert_equal [w], x.parents
+
+ w2 = ws[2]
+ w3 = ws[3]
+ assert_equal [w2], w3.parents
+ end
end
Please sign in to comment.
Something went wrong with that request. Please try again.