edge 0.1.0 → 0.2.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/README.md +10 -4
- data/Rakefile +12 -0
- data/lib/edge/forest.rb +51 -38
- data/lib/edge/version.rb +1 -1
- data/spec/forest_spec.rb +56 -29
- metadata +43 -14
    
        data/README.md
    CHANGED
    
    | @@ -32,18 +32,24 @@ acts_as_forest. | |
| 32 32 | 
             
                class Location < ActiveRecord::Base
         | 
| 33 33 | 
             
                  acts_as_forest :order => "name"
         | 
| 34 34 | 
             
                end
         | 
| 35 | 
            -
             | 
| 35 | 
            +
             | 
| 36 36 | 
             
                usa = Location.create! :name => "USA"
         | 
| 37 37 | 
             
                illinois = usa.children.create! :name => "Illinois"
         | 
| 38 38 | 
             
                chicago = illinois.children.create! :name => "Chicago"
         | 
| 39 39 | 
             
                indiana = usa.children.create! :name => "Indiana"
         | 
| 40 40 | 
             
                canada = Location.create! :name => "Canada"
         | 
| 41 41 | 
             
                british_columbia = canada.children.create! :name => "British Columbia"
         | 
| 42 | 
            -
             | 
| 42 | 
            +
             | 
| 43 43 | 
             
                Location.root.all # [usa, canada]
         | 
| 44 44 | 
             
                Location.find_forest # [usa, canada] with all children and parents preloaded
         | 
| 45 45 | 
             
                Location.find_tree usa.id # load a single tree.
         | 
| 46 46 |  | 
| 47 | 
            +
            It also provides the with_descendents scope to get all currently selected
         | 
| 48 | 
            +
            nodes and all there descendents. It can be chained after where scopes, but
         | 
| 49 | 
            +
            must not be used after any other type of scope.
         | 
| 50 | 
            +
             | 
| 51 | 
            +
                Location.where(name: "Illinois").with_descendents.all # [illinois, chicago]
         | 
| 52 | 
            +
             | 
| 47 53 | 
             
            ## Benchmarks
         | 
| 48 54 |  | 
| 49 55 | 
             
            Edge includes a performance benchmarks. You can create test forests with a
         | 
| @@ -58,7 +64,7 @@ size of payload per node. | |
| 58 64 | 
             
                    -p, --payload NUM                Characters of payload per node
         | 
| 59 65 |  | 
| 60 66 | 
             
            Even on slower machines entire trees can be loaded quickly.
         | 
| 61 | 
            -
             | 
| 67 | 
            +
             | 
| 62 68 | 
             
                jack@moya:~/work/edge$ ruby -I lib -I bench bench/forest_find.rb
         | 
| 63 69 | 
             
                Trees: 50
         | 
| 64 70 | 
             
                Depth: 3
         | 
| @@ -71,7 +77,7 @@ Even on slower machines entire trees can be loaded quickly. | |
| 71 77 | 
             
                Load one tree 100 times                    0.830000   0.040000   0.870000 (  0.984642)
         | 
| 72 78 |  | 
| 73 79 | 
             
            ### Running the benchmarks
         | 
| 74 | 
            -
             | 
| 80 | 
            +
             | 
| 75 81 | 
             
            1. Create a database such as edge_bench.
         | 
| 76 82 | 
             
            2. Configure bench/database.yml to connect to it.
         | 
| 77 83 | 
             
            3. Load bench/database_structure.sql into your bench database.
         | 
    
        data/Rakefile
    CHANGED
    
    | @@ -1,2 +1,14 @@ | |
| 1 1 | 
             
            #!/usr/bin/env rake
         | 
| 2 2 | 
             
            require "bundler/gem_tasks"
         | 
| 3 | 
            +
            require "rspec/core/rake_task"
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            RSpec::Core::RakeTask.new
         | 
| 6 | 
            +
            task :default => :spec
         | 
| 7 | 
            +
             | 
| 8 | 
            +
            namespace :db do
         | 
| 9 | 
            +
              desc 'bootstrap database'
         | 
| 10 | 
            +
              task :setup do
         | 
| 11 | 
            +
                sh "createdb edge_test"
         | 
| 12 | 
            +
                sh "psql edge_test < spec/database_structure.sql"
         | 
| 13 | 
            +
              end
         | 
| 14 | 
            +
            end
         | 
    
        data/lib/edge/forest.rb
    CHANGED
    
    | @@ -8,32 +8,32 @@ module Edge | |
| 8 8 | 
             
                  # * order - how to order children (default: none)
         | 
| 9 9 | 
             
                  def acts_as_forest(options={})
         | 
| 10 10 | 
             
                    options.assert_valid_keys :foreign_key, :order
         | 
| 11 | 
            -
             | 
| 11 | 
            +
             | 
| 12 12 | 
             
                    class_attribute :forest_foreign_key
         | 
| 13 13 | 
             
                    self.forest_foreign_key = options[:foreign_key] || "parent_id"
         | 
| 14 | 
            -
             | 
| 14 | 
            +
             | 
| 15 15 | 
             
                    class_attribute :forest_order
         | 
| 16 16 | 
             
                    self.forest_order = options[:order] || nil
         | 
| 17 | 
            -
             | 
| 17 | 
            +
             | 
| 18 18 | 
             
                    common_options = {
         | 
| 19 19 | 
             
                      :class_name => self,
         | 
| 20 20 | 
             
                      :foreign_key => forest_foreign_key
         | 
| 21 21 | 
             
                    }
         | 
| 22 | 
            -
             | 
| 22 | 
            +
             | 
| 23 23 | 
             
                    belongs_to :parent, common_options
         | 
| 24 | 
            -
             | 
| 24 | 
            +
             | 
| 25 25 | 
             
                    children_options = if forest_order
         | 
| 26 26 | 
             
                      common_options.merge(:order => forest_order)
         | 
| 27 27 | 
             
                    else
         | 
| 28 28 | 
             
                      common_options
         | 
| 29 29 | 
             
                    end
         | 
| 30 | 
            -
             | 
| 30 | 
            +
             | 
| 31 31 | 
             
                    has_many :children, children_options
         | 
| 32 | 
            -
             | 
| 32 | 
            +
             | 
| 33 33 | 
             
                    scope :root, where(forest_foreign_key => nil)
         | 
| 34 | 
            -
             | 
| 34 | 
            +
             | 
| 35 35 | 
             
                    include Edge::Forest::InstanceMethods
         | 
| 36 | 
            -
             | 
| 36 | 
            +
             | 
| 37 37 | 
             
                    # Finds entire forest and preloads all associations. It can be used at
         | 
| 38 38 | 
             
                    # the end of an ActiveRecord finder chain.
         | 
| 39 39 | 
             
                    #
         | 
| @@ -44,23 +44,9 @@ module Edge | |
| 44 44 | 
             
                    #    # loads all nodes with matching names and all there descendants
         | 
| 45 45 | 
             
                    #    Category.where(:name => %w{clothing books electronics}).find_forest
         | 
| 46 46 | 
             
                    def find_forest
         | 
| 47 | 
            -
                       | 
| 48 | 
            -
                          
         | 
| 49 | 
            -
                      original_term = (current_scope || scoped).arel
         | 
| 50 | 
            -
                      iterated_term = Arel::SelectManager.new Arel::Table.engine
         | 
| 51 | 
            -
                      iterated_term.from(arel_table)
         | 
| 52 | 
            -
                        .project(arel_table.columns)
         | 
| 53 | 
            -
                        .join(all_nodes)
         | 
| 54 | 
            -
                        .on(arel_table[forest_foreign_key].eq all_nodes[:id])
         | 
| 55 | 
            -
                      
         | 
| 56 | 
            -
                      union = original_term.union(iterated_term)
         | 
| 57 | 
            -
                      
         | 
| 58 | 
            -
                      as_statement = Arel::Nodes::As.new all_nodes, union
         | 
| 59 | 
            -
                      
         | 
| 60 | 
            -
                      manager = Arel::SelectManager.new Arel::Table.engine
         | 
| 61 | 
            -
                      manager.with(:recursive, as_statement).from(all_nodes).project(Arel.star)
         | 
| 47 | 
            +
                      manager = recursive_manager.project(Arel.star)
         | 
| 62 48 | 
             
                      manager.order(forest_order) if forest_order
         | 
| 63 | 
            -
             | 
| 49 | 
            +
             | 
| 64 50 | 
             
                      records = find_by_sql manager.to_sql
         | 
| 65 51 |  | 
| 66 52 | 
             
                      records_by_id = records.each_with_object({}) { |r, h| h[r.id] = r }
         | 
| @@ -72,7 +58,7 @@ module Edge | |
| 72 58 | 
             
                      end
         | 
| 73 59 |  | 
| 74 60 | 
             
                      top_level_records = []
         | 
| 75 | 
            -
             | 
| 61 | 
            +
             | 
| 76 62 | 
             
                      records.each do |r|
         | 
| 77 63 | 
             
                        parent = records_by_id[r[forest_foreign_key]]
         | 
| 78 64 | 
             
                        if parent
         | 
| @@ -82,10 +68,10 @@ module Edge | |
| 82 68 | 
             
                          top_level_records.push(r)
         | 
| 83 69 | 
             
                        end
         | 
| 84 70 | 
             
                      end
         | 
| 85 | 
            -
             | 
| 71 | 
            +
             | 
| 86 72 | 
             
                      top_level_records
         | 
| 87 73 | 
             
                    end
         | 
| 88 | 
            -
             | 
| 74 | 
            +
             | 
| 89 75 | 
             
                    # Finds an a tree or trees by id.
         | 
| 90 76 | 
             
                    #
         | 
| 91 77 | 
             
                    # If any requested ids are not found it raises
         | 
| @@ -100,44 +86,71 @@ module Edge | |
| 100 86 | 
             
                        trees.first
         | 
| 101 87 | 
             
                      end
         | 
| 102 88 | 
             
                    end
         | 
| 103 | 
            -
             | 
| 89 | 
            +
             | 
| 90 | 
            +
                    # Returns a new scope that includes previously scoped records and their descendants by subsuming the previous scope into a subquery
         | 
| 91 | 
            +
                    #
         | 
| 92 | 
            +
                    # Only where scopes can precede this in a scope chain
         | 
| 93 | 
            +
                    def with_descendants
         | 
| 94 | 
            +
                      manager = recursive_manager.project('id')
         | 
| 95 | 
            +
                      unscoped.where(id: manager)
         | 
| 96 | 
            +
                    end
         | 
| 97 | 
            +
             | 
| 98 | 
            +
                    private
         | 
| 99 | 
            +
                    def recursive_manager
         | 
| 100 | 
            +
                      all_nodes = Arel::Table.new(:all_nodes)
         | 
| 101 | 
            +
             | 
| 102 | 
            +
                      original_term = (current_scope || scoped).arel
         | 
| 103 | 
            +
                      iterated_term = Arel::SelectManager.new Arel::Table.engine
         | 
| 104 | 
            +
                      iterated_term.from(arel_table)
         | 
| 105 | 
            +
                        .project(arel_table.columns)
         | 
| 106 | 
            +
                        .join(all_nodes)
         | 
| 107 | 
            +
                        .on(arel_table[forest_foreign_key].eq all_nodes[:id])
         | 
| 108 | 
            +
             | 
| 109 | 
            +
                      union = original_term.union(iterated_term)
         | 
| 110 | 
            +
             | 
| 111 | 
            +
                      as_statement = Arel::Nodes::As.new all_nodes, union
         | 
| 112 | 
            +
             | 
| 113 | 
            +
                      manager = Arel::SelectManager.new Arel::Table.engine
         | 
| 114 | 
            +
                      manager.with(:recursive, as_statement).from(all_nodes)
         | 
| 115 | 
            +
                    end
         | 
| 116 | 
            +
                  end
         | 
| 104 117 | 
             
                end
         | 
| 105 | 
            -
             | 
| 118 | 
            +
             | 
| 106 119 | 
             
                module InstanceMethods
         | 
| 107 120 | 
             
                  # Returns the root of this node. If this node is root returns self.
         | 
| 108 121 | 
             
                  def root
         | 
| 109 122 | 
             
                    parent ? parent.root : self
         | 
| 110 123 | 
             
                  end
         | 
| 111 | 
            -
             | 
| 124 | 
            +
             | 
| 112 125 | 
             
                  # Returns true is this node is a root or false otherwise
         | 
| 113 126 | 
             
                  def root?
         | 
| 114 127 | 
             
                    !parent_id
         | 
| 115 128 | 
             
                  end
         | 
| 116 | 
            -
             | 
| 129 | 
            +
             | 
| 117 130 | 
             
                  # Returns all sibling nodes (nodes that have the same parent). If this
         | 
| 118 | 
            -
                  # node is a root node it returns an empty array. | 
| 131 | 
            +
                  # node is a root node it returns an empty array.
         | 
| 119 132 | 
             
                  def siblings
         | 
| 120 133 | 
             
                    parent ? parent.children - [self] : []
         | 
| 121 134 | 
             
                  end
         | 
| 122 | 
            -
             | 
| 123 | 
            -
                  # Returns all ancestors ordered by nearest ancestors first. | 
| 135 | 
            +
             | 
| 136 | 
            +
                  # Returns all ancestors ordered by nearest ancestors first.
         | 
| 124 137 | 
             
                  def ancestors
         | 
| 125 138 | 
             
                    _ancestors = []
         | 
| 126 139 | 
             
                    node = self
         | 
| 127 140 | 
             
                    while(node = node.parent)
         | 
| 128 141 | 
             
                      _ancestors.push(node)
         | 
| 129 142 | 
             
                    end
         | 
| 130 | 
            -
             | 
| 143 | 
            +
             | 
| 131 144 | 
             
                    _ancestors
         | 
| 132 145 | 
             
                  end
         | 
| 133 | 
            -
             | 
| 146 | 
            +
             | 
| 134 147 | 
             
                  # Returns all descendants
         | 
| 135 148 | 
             
                  def descendants
         | 
| 136 149 | 
             
                    if children.present?
         | 
| 137 150 | 
             
                      children + children.map(&:descendants).flatten
         | 
| 138 151 | 
             
                    else
         | 
| 139 152 | 
             
                      []
         | 
| 140 | 
            -
                    end | 
| 153 | 
            +
                    end
         | 
| 141 154 | 
             
                  end
         | 
| 142 155 | 
             
                end
         | 
| 143 156 | 
             
              end
         | 
    
        data/lib/edge/version.rb
    CHANGED
    
    
    
        data/spec/forest_spec.rb
    CHANGED
    
    | @@ -8,28 +8,28 @@ describe "Edge::Forest" do | |
| 8 8 | 
             
              let!(:usa) { Location.create! :name => "USA" }
         | 
| 9 9 | 
             
              let!(:illinois) { Location.create! :parent => usa, :name => "Illinois" }
         | 
| 10 10 | 
             
              let!(:chicago) { Location.create! :parent => illinois, :name => "Chicago" }
         | 
| 11 | 
            -
              let!(:indiana) { Location.create! :parent => usa, :name => "Indiana" } | 
| 11 | 
            +
              let!(:indiana) { Location.create! :parent => usa, :name => "Indiana" }
         | 
| 12 12 | 
             
              let!(:canada) { Location.create! :name => "Canada" }
         | 
| 13 13 | 
             
              let!(:british_columbia) { Location.create! :parent => canada, :name => "British Columbia" }
         | 
| 14 | 
            -
             | 
| 14 | 
            +
             | 
| 15 15 | 
             
              describe "root?" do
         | 
| 16 16 | 
             
                context "of root node" do
         | 
| 17 17 | 
             
                  it "should be true" do
         | 
| 18 18 | 
             
                    usa.root?.should == true
         | 
| 19 19 | 
             
                  end
         | 
| 20 20 | 
             
                end
         | 
| 21 | 
            -
             | 
| 21 | 
            +
             | 
| 22 22 | 
             
                context "of child node" do
         | 
| 23 23 | 
             
                  it "should be false" do
         | 
| 24 24 | 
             
                    illinois.root?.should == false
         | 
| 25 25 | 
             
                  end
         | 
| 26 26 | 
             
                end
         | 
| 27 | 
            -
             | 
| 27 | 
            +
             | 
| 28 28 | 
             
                context "of leaf node" do
         | 
| 29 29 | 
             
                  it "should be root node" do
         | 
| 30 30 | 
             
                    chicago.root?.should == false
         | 
| 31 31 | 
             
                  end
         | 
| 32 | 
            -
                end | 
| 32 | 
            +
                end
         | 
| 33 33 | 
             
              end
         | 
| 34 34 |  | 
| 35 35 | 
             
              describe "root" do
         | 
| @@ -38,103 +38,103 @@ describe "Edge::Forest" do | |
| 38 38 | 
             
                    usa.root.should == usa
         | 
| 39 39 | 
             
                  end
         | 
| 40 40 | 
             
                end
         | 
| 41 | 
            -
             | 
| 41 | 
            +
             | 
| 42 42 | 
             
                context "of child node" do
         | 
| 43 43 | 
             
                  it "should be root node" do
         | 
| 44 44 | 
             
                    illinois.root.should == usa
         | 
| 45 45 | 
             
                  end
         | 
| 46 46 | 
             
                end
         | 
| 47 | 
            -
             | 
| 47 | 
            +
             | 
| 48 48 | 
             
                context "of leaf node" do
         | 
| 49 49 | 
             
                  it "should be root node" do
         | 
| 50 50 | 
             
                    chicago.root.should == usa
         | 
| 51 51 | 
             
                  end
         | 
| 52 52 | 
             
                end
         | 
| 53 53 | 
             
              end
         | 
| 54 | 
            -
             | 
| 54 | 
            +
             | 
| 55 55 | 
             
              describe "parent" do
         | 
| 56 56 | 
             
                context "of root node" do
         | 
| 57 57 | 
             
                  it "should be nil" do
         | 
| 58 58 | 
             
                    usa.parent.should == nil
         | 
| 59 59 | 
             
                  end
         | 
| 60 60 | 
             
                end
         | 
| 61 | 
            -
             | 
| 61 | 
            +
             | 
| 62 62 | 
             
                context "of child node" do
         | 
| 63 63 | 
             
                  it "should be parent" do
         | 
| 64 64 | 
             
                    illinois.parent.should == usa
         | 
| 65 65 | 
             
                  end
         | 
| 66 66 | 
             
                end
         | 
| 67 | 
            -
             | 
| 67 | 
            +
             | 
| 68 68 | 
             
                context "of leaf node" do
         | 
| 69 69 | 
             
                  it "should be parent" do
         | 
| 70 70 | 
             
                    chicago.parent.should == illinois
         | 
| 71 71 | 
             
                  end
         | 
| 72 72 | 
             
                end
         | 
| 73 73 | 
             
              end
         | 
| 74 | 
            -
             | 
| 74 | 
            +
             | 
| 75 75 | 
             
              describe "ancestors" do
         | 
| 76 76 | 
             
                context "of root node" do
         | 
| 77 77 | 
             
                  it "should be empty" do
         | 
| 78 78 | 
             
                    usa.ancestors.should be_empty
         | 
| 79 79 | 
             
                  end
         | 
| 80 80 | 
             
                end
         | 
| 81 | 
            -
             | 
| 81 | 
            +
             | 
| 82 82 | 
             
                context "of leaf node" do
         | 
| 83 83 | 
             
                  it "should be ancestors ordered by ascending distance" do
         | 
| 84 84 | 
             
                    chicago.ancestors.should == [illinois, usa]
         | 
| 85 85 | 
             
                  end
         | 
| 86 86 | 
             
                end
         | 
| 87 87 | 
             
              end
         | 
| 88 | 
            -
             | 
| 88 | 
            +
             | 
| 89 89 | 
             
              describe "siblings" do
         | 
| 90 90 | 
             
                context "of root node" do
         | 
| 91 91 | 
             
                  it "should be empty" do
         | 
| 92 92 | 
             
                    usa.siblings.should be_empty
         | 
| 93 93 | 
             
                  end
         | 
| 94 94 | 
             
                end
         | 
| 95 | 
            -
             | 
| 95 | 
            +
             | 
| 96 96 | 
             
                context "of child node" do
         | 
| 97 97 | 
             
                  it "should be other children of parent" do
         | 
| 98 98 | 
             
                    illinois.siblings.should include(indiana)
         | 
| 99 99 | 
             
                  end
         | 
| 100 100 | 
             
                end
         | 
| 101 101 | 
             
              end
         | 
| 102 | 
            -
             | 
| 102 | 
            +
             | 
| 103 103 | 
             
              describe "children" do
         | 
| 104 104 | 
             
                it "should be children" do
         | 
| 105 105 | 
             
                  usa.children.should include(illinois, indiana)
         | 
| 106 106 | 
             
                end
         | 
| 107 | 
            -
             | 
| 107 | 
            +
             | 
| 108 108 | 
             
                it "should be ordered" do
         | 
| 109 109 | 
             
                  alabama = Location.create! :parent => usa, :name => "Alabama"
         | 
| 110 110 | 
             
                  usa.children.should == [alabama, illinois, indiana]
         | 
| 111 111 | 
             
                end
         | 
| 112 | 
            -
             | 
| 112 | 
            +
             | 
| 113 113 | 
             
                context "of leaf" do
         | 
| 114 114 | 
             
                  it "should be empty" do
         | 
| 115 115 | 
             
                    chicago.children.should be_empty
         | 
| 116 116 | 
             
                  end
         | 
| 117 117 | 
             
                end
         | 
| 118 118 | 
             
              end
         | 
| 119 | 
            -
             | 
| 119 | 
            +
             | 
| 120 120 | 
             
              describe "descendants" do
         | 
| 121 121 | 
             
                it "should be all descendants" do
         | 
| 122 122 | 
             
                  usa.descendants.should include(illinois, indiana, chicago)
         | 
| 123 123 | 
             
                end
         | 
| 124 | 
            -
             | 
| 124 | 
            +
             | 
| 125 125 | 
             
                context "of leaf" do
         | 
| 126 126 | 
             
                  it "should be empty" do
         | 
| 127 127 | 
             
                    chicago.descendants.should be_empty
         | 
| 128 128 | 
             
                  end
         | 
| 129 129 | 
             
                end
         | 
| 130 130 | 
             
              end
         | 
| 131 | 
            -
             | 
| 131 | 
            +
             | 
| 132 132 | 
             
              describe "root scope" do
         | 
| 133 133 | 
             
                it "returns only root nodes" do
         | 
| 134 134 | 
             
                  Location.root.all.should include(usa, canada)
         | 
| 135 135 | 
             
                end
         | 
| 136 136 | 
             
              end
         | 
| 137 | 
            -
             | 
| 137 | 
            +
             | 
| 138 138 | 
             
              describe "find_forest" do
         | 
| 139 139 | 
             
                it "preloads all parents and children" do
         | 
| 140 140 | 
             
                  forest = Location.find_forest
         | 
| @@ -150,39 +150,66 @@ describe "Edge::Forest" do | |
| 150 150 | 
             
                    end
         | 
| 151 151 | 
             
                  end
         | 
| 152 152 | 
             
                end
         | 
| 153 | 
            -
             | 
| 153 | 
            +
             | 
| 154 154 | 
             
                it "works when scoped" do
         | 
| 155 155 | 
             
                  forest = Location.where(:name => "USA").find_forest
         | 
| 156 156 | 
             
                  forest.should include(usa)
         | 
| 157 157 | 
             
                end
         | 
| 158 | 
            -
             | 
| 158 | 
            +
             | 
| 159 159 | 
             
                it "preloads children in proper order" do
         | 
| 160 160 | 
             
                  alabama = Location.create! :parent => usa, :name => "Alabama"
         | 
| 161 161 | 
             
                  forest = Location.find_forest
         | 
| 162 162 | 
             
                  tree = forest.find { |l| l.id == usa.id }
         | 
| 163 163 | 
             
                  tree.children.should == [alabama, illinois, indiana]
         | 
| 164 164 | 
             
                end
         | 
| 165 | 
            +
             | 
| 166 | 
            +
                context "with an infinite loop" do
         | 
| 167 | 
            +
                  before do
         | 
| 168 | 
            +
                    usa.update_attribute(:parent, chicago)
         | 
| 169 | 
            +
                  end
         | 
| 170 | 
            +
             | 
| 171 | 
            +
                  it "does not re-loop" do
         | 
| 172 | 
            +
                    Location.find_forest
         | 
| 173 | 
            +
                  end
         | 
| 174 | 
            +
                end
         | 
| 165 175 | 
             
              end
         | 
| 166 | 
            -
             | 
| 176 | 
            +
             | 
| 167 177 | 
             
              describe "find_tree" do
         | 
| 168 178 | 
             
                it "finds by id" do
         | 
| 169 179 | 
             
                  tree = Location.find_tree usa.id
         | 
| 170 180 | 
             
                  tree.should == usa
         | 
| 171 181 | 
             
                end
         | 
| 172 | 
            -
             | 
| 182 | 
            +
             | 
| 173 183 | 
             
                it "finds multiple trees by id" do
         | 
| 174 184 | 
             
                  trees = Location.find_tree [indiana.id, illinois.id]
         | 
| 175 185 | 
             
                  trees.should include(indiana, illinois)
         | 
| 176 186 | 
             
                end
         | 
| 177 | 
            -
             | 
| 187 | 
            +
             | 
| 178 188 | 
             
                it "raises ActiveRecord::RecordNotFound when id is not found" do
         | 
| 179 189 | 
             
                  expect{Location.find_tree -1}.to raise_error(ActiveRecord::RecordNotFound)
         | 
| 180 190 | 
             
                end
         | 
| 181 | 
            -
             | 
| 191 | 
            +
             | 
| 182 192 | 
             
                it "raises ActiveRecord::RecordNotFound when not all ids are not found" do
         | 
| 183 193 | 
             
                  expect{Location.find_tree [indiana.id, -1]}.to raise_error(ActiveRecord::RecordNotFound)
         | 
| 184 194 | 
             
                end
         | 
| 185 | 
            -
             | 
| 195 | 
            +
             | 
| 196 | 
            +
              end
         | 
| 197 | 
            +
             | 
| 198 | 
            +
              describe "with_descendants" do
         | 
| 199 | 
            +
                context "unscoped" do
         | 
| 200 | 
            +
                  it "returns all records" do
         | 
| 201 | 
            +
                    Location.with_descendants.all.should =~ Location.all
         | 
| 202 | 
            +
                  end
         | 
| 203 | 
            +
                end
         | 
| 204 | 
            +
             | 
| 205 | 
            +
                context "scoped" do
         | 
| 206 | 
            +
                  it "returns a new scope that includes previously scoped records and their descendants" do
         | 
| 207 | 
            +
                    Location.where(id: canada.id).with_descendants.all.should =~ [canada, british_columbia]
         | 
| 208 | 
            +
                  end
         | 
| 209 | 
            +
             | 
| 210 | 
            +
                  it "is not commutative" do
         | 
| 211 | 
            +
                    Location.with_descendants.where(id: canada.id).all.should == [canada]
         | 
| 212 | 
            +
                  end
         | 
| 213 | 
            +
                end
         | 
| 186 214 | 
             
              end
         | 
| 187 | 
            -
              
         | 
| 188 215 | 
             
            end
         | 
    
        metadata
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            --- !ruby/object:Gem::Specification
         | 
| 2 2 | 
             
            name: edge
         | 
| 3 3 | 
             
            version: !ruby/object:Gem::Version
         | 
| 4 | 
            -
              version: 0. | 
| 4 | 
            +
              version: 0.2.0
         | 
| 5 5 | 
             
              prerelease: 
         | 
| 6 6 | 
             
            platform: ruby
         | 
| 7 7 | 
             
            authors:
         | 
| @@ -9,11 +9,11 @@ authors: | |
| 9 9 | 
             
            autorequire: 
         | 
| 10 10 | 
             
            bindir: bin
         | 
| 11 11 | 
             
            cert_chain: []
         | 
| 12 | 
            -
            date:  | 
| 12 | 
            +
            date: 2013-02-22 00:00:00.000000000 Z
         | 
| 13 13 | 
             
            dependencies:
         | 
| 14 14 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 15 15 | 
             
              name: activerecord
         | 
| 16 | 
            -
              requirement:  | 
| 16 | 
            +
              requirement: !ruby/object:Gem::Requirement
         | 
| 17 17 | 
             
                none: false
         | 
| 18 18 | 
             
                requirements:
         | 
| 19 19 | 
             
                - - ! '>='
         | 
| @@ -21,10 +21,15 @@ dependencies: | |
| 21 21 | 
             
                    version: 3.2.0
         | 
| 22 22 | 
             
              type: :runtime
         | 
| 23 23 | 
             
              prerelease: false
         | 
| 24 | 
            -
              version_requirements:  | 
| 24 | 
            +
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 25 | 
            +
                none: false
         | 
| 26 | 
            +
                requirements:
         | 
| 27 | 
            +
                - - ! '>='
         | 
| 28 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 29 | 
            +
                    version: 3.2.0
         | 
| 25 30 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 26 31 | 
             
              name: pg
         | 
| 27 | 
            -
              requirement:  | 
| 32 | 
            +
              requirement: !ruby/object:Gem::Requirement
         | 
| 28 33 | 
             
                none: false
         | 
| 29 34 | 
             
                requirements:
         | 
| 30 35 | 
             
                - - ! '>='
         | 
| @@ -32,10 +37,15 @@ dependencies: | |
| 32 37 | 
             
                    version: '0'
         | 
| 33 38 | 
             
              type: :development
         | 
| 34 39 | 
             
              prerelease: false
         | 
| 35 | 
            -
              version_requirements:  | 
| 40 | 
            +
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 41 | 
            +
                none: false
         | 
| 42 | 
            +
                requirements:
         | 
| 43 | 
            +
                - - ! '>='
         | 
| 44 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 45 | 
            +
                    version: '0'
         | 
| 36 46 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 37 47 | 
             
              name: rspec
         | 
| 38 | 
            -
              requirement:  | 
| 48 | 
            +
              requirement: !ruby/object:Gem::Requirement
         | 
| 39 49 | 
             
                none: false
         | 
| 40 50 | 
             
                requirements:
         | 
| 41 51 | 
             
                - - ~>
         | 
| @@ -43,10 +53,15 @@ dependencies: | |
| 43 53 | 
             
                    version: 2.8.0
         | 
| 44 54 | 
             
              type: :development
         | 
| 45 55 | 
             
              prerelease: false
         | 
| 46 | 
            -
              version_requirements:  | 
| 56 | 
            +
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 57 | 
            +
                none: false
         | 
| 58 | 
            +
                requirements:
         | 
| 59 | 
            +
                - - ~>
         | 
| 60 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 61 | 
            +
                    version: 2.8.0
         | 
| 47 62 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 48 63 | 
             
              name: guard
         | 
| 49 | 
            -
              requirement:  | 
| 64 | 
            +
              requirement: !ruby/object:Gem::Requirement
         | 
| 50 65 | 
             
                none: false
         | 
| 51 66 | 
             
                requirements:
         | 
| 52 67 | 
             
                - - ! '>='
         | 
| @@ -54,10 +69,15 @@ dependencies: | |
| 54 69 | 
             
                    version: 0.10.0
         | 
| 55 70 | 
             
              type: :development
         | 
| 56 71 | 
             
              prerelease: false
         | 
| 57 | 
            -
              version_requirements:  | 
| 72 | 
            +
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 73 | 
            +
                none: false
         | 
| 74 | 
            +
                requirements:
         | 
| 75 | 
            +
                - - ! '>='
         | 
| 76 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 77 | 
            +
                    version: 0.10.0
         | 
| 58 78 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 59 79 | 
             
              name: guard-rspec
         | 
| 60 | 
            -
              requirement:  | 
| 80 | 
            +
              requirement: !ruby/object:Gem::Requirement
         | 
| 61 81 | 
             
                none: false
         | 
| 62 82 | 
             
                requirements:
         | 
| 63 83 | 
             
                - - ! '>='
         | 
| @@ -65,7 +85,12 @@ dependencies: | |
| 65 85 | 
             
                    version: 0.6.0
         | 
| 66 86 | 
             
              type: :development
         | 
| 67 87 | 
             
              prerelease: false
         | 
| 68 | 
            -
              version_requirements:  | 
| 88 | 
            +
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 89 | 
            +
                none: false
         | 
| 90 | 
            +
                requirements:
         | 
| 91 | 
            +
                - - ! '>='
         | 
| 92 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 93 | 
            +
                    version: 0.6.0
         | 
| 69 94 | 
             
            description: Graph functionality for ActiveRecord
         | 
| 70 95 | 
             
            email:
         | 
| 71 96 | 
             
            - jack@jackchristensen.com
         | 
| @@ -112,9 +137,13 @@ required_rubygems_version: !ruby/object:Gem::Requirement | |
| 112 137 | 
             
                  version: '0'
         | 
| 113 138 | 
             
            requirements: []
         | 
| 114 139 | 
             
            rubyforge_project: 
         | 
| 115 | 
            -
            rubygems_version: 1.8. | 
| 140 | 
            +
            rubygems_version: 1.8.23
         | 
| 116 141 | 
             
            signing_key: 
         | 
| 117 142 | 
             
            specification_version: 3
         | 
| 118 143 | 
             
            summary: Graph functionality for ActiveRecord. Provides tree/forest modeling structure
         | 
| 119 144 | 
             
              that can load entire trees in a single query.
         | 
| 120 | 
            -
            test_files: | 
| 145 | 
            +
            test_files:
         | 
| 146 | 
            +
            - spec/database.yml
         | 
| 147 | 
            +
            - spec/database_structure.sql
         | 
| 148 | 
            +
            - spec/forest_spec.rb
         | 
| 149 | 
            +
            - spec/spec_helper.rb
         |