lib/nested_set/base.rb in nested_set-1.5.4 vs lib/nested_set/base.rb in nested_set-1.6.0

- old
+ new

@@ -97,11 +97,11 @@ } scope :leaves, lambda { where("#{quoted_right_column_name} - #{quoted_left_column_name} = 1"). order(quoted_left_column_name) } - scope :with_depth, proc {|level| where(:depth => level).order("lft") } + scope :with_depth, proc {|level| where(:depth => level).order(quoted_left_column_name) } define_callbacks :move, :terminator => "result == false" end end end @@ -111,10 +111,46 @@ # Returns the first root def root roots.first end + # Returns arranged nodes hash. + # I.e. you have this tree: + # + # 1 + # 2 + # 3 + # 4 + # 5 + # 6 + # 7 + # + # Hash will looks like: + # + # {1 => {2 => {}, 3 => {4 => {5 => {}}, 6 => {}}}, 7 => {}} + # + # == Usage: + # + # Categories.arrange + # Categories.find(42).children.arrange + # Categories.find(42).descendants.arrange + # Categories.find(42).self_and_descendants.arrange + # + # This arranged hash can be rendered with recursive render_tree helper + def arrange + arranged = ActiveSupport::OrderedHash.new + insertion_points = [arranged] + depth = 0 + order(quoted_left_column_name).each_with_level do |node, level| + insertion_points.push insertion_points.last.values.last if level > depth + (depth - level).times { insertion_points.pop } if level < depth + insertion_points.last.merge! node => ActiveSupport::OrderedHash.new + depth = level + end + arranged + end + def valid? left_and_rights_valid? && no_duplicates_for_columns? && all_roots_valid? end def left_and_rights_valid? @@ -208,22 +244,20 @@ # because it doesn't require any additional database queries. # # Example: # Category.each_with_level(Category.root.self_and_descendants) do |o, level| # - def each_with_level(objects) - path = [nil] - objects.each do |o| - if o.parent_id != path.last - # we are on a new level, did we decent or ascent? - if path.include?(o.parent_id) - # remove wrong wrong tailing paths elements - path.pop while path.last != o.parent_id - else - path << o.parent_id - end + + def each_with_level(objects = nil) + levels = [] + (objects || scoped).each do |i| + if level = levels.index(i.parent_id) + levels.slice!((level + 1)..-1) + else + levels << i.parent_id + level = levels.size - 1 end - yield(o, path.length - 1) + yield(i, level) end end def before_move(*args, &block) set_callback :move, :before, *args, &block