0

I am learning rails and have come across the following code which I would like to use. The code in question is the answer by John F Miller (first answer) in the following link: How to render all records from a nested set into a real html tree

def tree_from_set(set) #set must be in order
  buf = START_TAG(set[0])
  stack = []
  stack.push set[0]
  set[1..-1].each do |node|
    if stack.last.lft < node.lft < stack.last.rgt
      if node.leaf? #(node.rgt - node.lft == 1)
        buf << NODE_TAG(node)
      else
        buf << START_TAG(node)
        stack.push(node)
      end
    else#
      buf << END_TAG
      stack.pop
      retry
    end
  end
  buf <<END_TAG
end

def START_TAG(node) #for example
  "<li><p>#{node.name}</p><ul>"
end

def NODE_TAG(node)
  "<li><p>#{node.name}</p></li>"
end

def END_TAG
  "</li></ul>"
end

I am unsure of the following and would appreciate any guidance.

I see this will cycle through "set" assigning each item to the object "node" however I cannot determine what [1..-1] does.

set[1..-1].each do |node|

Following the logic I cannot understand the purpose of removing the last item from the array "stack"

stack.pop

It appears this command in this context is no longer supported in ruby after 1.9. I believe the intention was to return to the start of the loop and repeat.

retry
Community
  • 1
  • 1
Dercni
  • 1,216
  • 3
  • 18
  • 38

1 Answers1

1

A "subarray" with all but zeroth element.

Negative array indices -x in Ruby are shorthands for length-x. That is, -1'st element is the last. Range 1..-1 is "first to last", but since arrays are zero-indexed in Ruby, that means "all but zeroth element".

The stack holds "how deep you are", more precisely, which elements are you currently in. When examining the next element, if you "went out", you should close the list you left (possibly multiple times!) before adding the current item.

As for retry: I think it should be redo. If you stepped outside, you have to make sure you close every list you have to: once per iteration you pop from the stack, close the closest list and loop this until you are inside the top element on the stack, in the context for the current node to be inserted.

Actually, thus code assumes you only have one tree with set[0] its root. By adding to line 6 a check (with ||) if the stack is empty you eliminate this flaw, need for pushing set[0] manually, and thus exclusion of it from the loop. Because if the stack is empty, you are in hyperspace that contains everything, so you shouldn't bother comparing anything. This gives you the possibility of rendering multiple element trees (possibly without common root) from one list.

I believe the clean solution to this is a recursive one, replacing "home-made stack" with Ruby's call stack. I can't come up with a solution too quickly on this though.

D-side
  • 9,150
  • 3
  • 28
  • 44
  • Thanks for the great feedback. From what I have read retry and redo are different: http://rubyquicktips.com/post/1122838559/redo-vs-retry – Dercni Nov 10 '14 at 02:51
  • @user1567212 They are, `retry` is now mostly used for exception handling, from what I've seen. – D-side Nov 10 '14 at 11:11
  • My next challenge is to display the leaf nodes in alphabetical order. My initial thoughts are this would be a three step process. (1) modify above to read nodes into a multi dimension array, (2) sort elements within arrays, (3) loop through array to output html. Does this sound right? – Dercni Nov 10 '14 at 21:01
  • @user1567212 I would enforce that order on the database level. Digging around gem's sources might give something. I'll try. – D-side Nov 10 '14 at 21:16
  • @user1567212 check this out: https://github.com/collectiveidea/awesome_nested_set/pull/96 it's not database level, but should work. Similar to what you've been suggesting. – D-side Nov 10 '14 at 21:28
  • After looking into this more I'm going to have a go at implementing this at the database level. Thinking it through upon insert I'd need to isolate the sibling nodes and then work out where in the order the new node goes, make a gap and write the new record. – Dercni Nov 11 '14 at 02:10