closure_tree 3.0.4 → 3.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -9,6 +9,12 @@ See [Bill Karwin](http://karwin.blogspot.com/)'s excellent
9
9
  [Models for hierarchical data presentation](http://www.slideshare.net/billkarwin/models-for-hierarchical-data)
10
10
  for a description of different tree storage algorithms.
11
11
 
12
+ Closure tree is [tested under every combination](https://secure.travis-ci.org/mceachen/closure_tree.png?branch=master) of
13
+
14
+ * Ruby 1.8.7 and Ruby 1.9.3
15
+ * The latest Rails 3.0, 3.1, and 3.2 branches, and
16
+ * Using MySQL, Postgresql, and SQLite.
17
+
12
18
  ## Installation
13
19
 
14
20
  Note that closure_tree only supports Rails 3.0 and later, and has test coverage for MySQL, PostgreSQL, and SQLite.
@@ -181,6 +187,10 @@ class WhatTag < Tag ; end
181
187
 
182
188
  ## Change log
183
189
 
190
+ ### 3.1.0
191
+
192
+ * Switched to using ```has_many :though``` rather than ```has_and_belongs_to_many```
193
+
184
194
  ### 3.0.4
185
195
 
186
196
  * Merged [pull request](https://github.com/mceachen/closure_tree/pull/8) to fix ```.siblings``` and ```.self_and_siblings```
@@ -24,6 +24,11 @@ module ClosureTree
24
24
  belongs_to :ancestor, :class_name => "#{ct_class.to_s}"
25
25
  belongs_to :descendant, :class_name => "#{ct_class.to_s}"
26
26
  attr_accessible :ancestor, :descendant, :generations
27
+ def ==(comparison_object)
28
+ comparison_object.instance_of?(self.class) &&
29
+ self.attributes == comparison_object.attributes
30
+ end
31
+ alias :eql? :==
27
32
  RUBY
28
33
 
29
34
  include ClosureTree::Model
@@ -42,18 +47,26 @@ module ClosureTree
42
47
  :foreign_key => parent_column_name,
43
48
  :dependent => closure_tree_options[:dependent]
44
49
 
45
- has_and_belongs_to_many :self_and_ancestors,
46
- :class_name => ct_class.to_s,
47
- :join_table => hierarchy_table_name,
50
+ has_many :ancestor_hierarchies,
51
+ :class_name => hierarchy_class_name,
48
52
  :foreign_key => "descendant_id",
49
- :association_foreign_key => "ancestor_id",
53
+ :order => "generations asc",
54
+ :dependent => :destroy
55
+
56
+ has_many :self_and_ancestors,
57
+ :through => :ancestor_hierarchies,
58
+ :source => :ancestor,
50
59
  :order => "generations asc"
51
60
 
52
- has_and_belongs_to_many :self_and_descendants,
53
- :class_name => ct_class.to_s,
54
- :join_table => hierarchy_table_name,
61
+ has_many :descendant_hierarchies,
62
+ :class_name => hierarchy_class_name,
55
63
  :foreign_key => "ancestor_id",
56
- :association_foreign_key => "descendant_id",
64
+ :order => "generations asc",
65
+ :dependent => :destroy
66
+
67
+ has_many :self_and_descendants,
68
+ :through => :descendant_hierarchies,
69
+ :source => :descendant,
57
70
  :order => "generations asc"
58
71
 
59
72
  scope :roots, where(parent_column_name => nil)
@@ -71,7 +84,7 @@ module ClosureTree
71
84
 
72
85
  # Returns true if this node has no parents.
73
86
  def root?
74
- parent.nil?
87
+ _parent_id.nil?
75
88
  end
76
89
 
77
90
  # Returns true if this node has a parent, and is not a root.
@@ -86,7 +99,7 @@ module ClosureTree
86
99
 
87
100
  # Returns the farthest ancestor, or self if +root?+
88
101
  def root
89
- root? ? self : ancestors.last
102
+ self_and_ancestors.where(parent_column_name.to_sym => nil).first
90
103
  end
91
104
 
92
105
  def leaves
@@ -136,7 +149,7 @@ module ClosureTree
136
149
 
137
150
  # Find a child node whose +ancestry_path+ minus self.ancestry_path is +path+.
138
151
  def find_by_path(path)
139
- path = [path] unless path.is_a? Enumerable
152
+ path = path.is_a?(Enumerable) ? path.dup : [path]
140
153
  node = self
141
154
  while !path.empty? && node
142
155
  node = node.children.send("find_by_#{name_column}", path.shift)
@@ -146,7 +159,7 @@ module ClosureTree
146
159
 
147
160
  # Find a child node whose +ancestry_path+ minus self.ancestry_path is +path+
148
161
  def find_or_create_by_path(path, attributes = {})
149
- path = [path] unless path.is_a? Enumerable
162
+ path = path.is_a?(Enumerable) ? path.dup : [path]
150
163
  node = self
151
164
  attrs = {}
152
165
  attrs[:type] = self.type if ct_subclass? && ct_has_type?
@@ -1,3 +1,3 @@
1
1
  module ClosureTree
2
- VERSION = "3.0.4" unless defined?(::ClosureTree::VERSION)
2
+ VERSION = "3.1.0" unless defined?(::ClosureTree::VERSION)
3
3
  end
@@ -6,7 +6,6 @@ shared_examples_for Tag do
6
6
  def nuke_db
7
7
  Tag.delete_all
8
8
  TagHierarchy.delete_all
9
- DestroyedTag.delete_all
10
9
  end
11
10
 
12
11
  before :each do
@@ -42,6 +41,7 @@ shared_examples_for Tag do
42
41
  @root = Tag.create! :name => "root"
43
42
  @mid = @root.children.create! :name => "mid"
44
43
  @leaf = @mid.children.create! :name => "leaf"
44
+ DestroyedTag.delete_all
45
45
  end
46
46
 
47
47
  it "should create all tags" do
@@ -100,6 +100,23 @@ shared_examples_for Tag do
100
100
  @root.children << @leaf
101
101
  Tag.leaves.should =~ [@leaf, @mid]
102
102
  end
103
+
104
+ it "cleans up hierarchy references for leaves" do
105
+ @leaf.destroy
106
+ TagHierarchy.find_all_by_ancestor_id(@leaf.id).should be_empty
107
+ TagHierarchy.find_all_by_descendant_id(@leaf.id).should be_empty
108
+ end
109
+
110
+ it "cleans up hierarchy references" do
111
+ @mid.destroy
112
+ TagHierarchy.find_all_by_ancestor_id(@mid.id).should be_empty
113
+ TagHierarchy.find_all_by_descendant_id(@mid.id).should be_empty
114
+ @root.reload.should be_root
115
+ root_hiers = @root.ancestor_hierarchies.to_a
116
+ root_hiers.size.should == 1
117
+ TagHierarchy.find_all_by_ancestor_id(@root.id).should == root_hiers
118
+ TagHierarchy.find_all_by_descendant_id(@root.id).should == root_hiers
119
+ end
103
120
  end
104
121
  end
105
122
 
@@ -109,6 +126,7 @@ shared_examples_for Tag do
109
126
 
110
127
  before :each do
111
128
  Tag.rebuild!
129
+ DestroyedTag.delete_all
112
130
  end
113
131
 
114
132
  context "class injection" do
@@ -199,8 +217,8 @@ shared_examples_for Tag do
199
217
  l1 = Tag.find_or_create_by_path(%w{roottest1 branch1 leaf1})
200
218
  l2 = Tag.find_or_create_by_path(%w{roottest2 branch2 leaf2})
201
219
  l1.children << l2.root
202
- l1.ancestry_path.should == %w{roottest1 branch1 leaf1}
203
- l2.ancestry_path.should == %w{roottest1 branch1 leaf1 roottest2 branch2 leaf2}
220
+ l1.reload.ancestry_path.should == %w{roottest1 branch1 leaf1}
221
+ l2.reload.ancestry_path.should == %w{roottest1 branch1 leaf1 roottest2 branch2 leaf2}
204
222
  end
205
223
 
206
224
  it "should cascade delete all children" do
@@ -238,12 +256,12 @@ shared_examples_for Tag do
238
256
  tags(:a1).self_and_siblings.to_a.should =~ Tag.roots.to_a
239
257
  end
240
258
 
241
- it "should assemble ancestors correctly" do
259
+ it "assembles ancestors" do
242
260
  tags(:child).ancestors.should == [tags(:parent), tags(:grandparent)]
243
261
  tags(:child).self_and_ancestors.should == [tags(:child), tags(:parent), tags(:grandparent)]
244
262
  end
245
263
 
246
- it "should assemble descendants correctly" do
264
+ it "assembles descendants" do
247
265
  tags(:parent).descendants.should == [tags(:child)]
248
266
  tags(:parent).self_and_descendants.should == [tags(:parent), tags(:child)]
249
267
  tags(:grandparent).descendants.should == [tags(:parent), tags(:child)]
@@ -37,6 +37,7 @@ describe "empty db" do
37
37
  @root = User.create! :email => "poppy@t.co"
38
38
  @mid = @root.children.create! :email => "matt@t.co"
39
39
  @leaf = @mid.children.create! :email => "james@t.co"
40
+ @root_id = @root.id
40
41
  end
41
42
 
42
43
  it "should create all Users" do
@@ -63,13 +64,15 @@ describe "empty db" do
63
64
  @root.destroy
64
65
  assert_mid_and_leaf_remain
65
66
  end
66
- end
67
- end
68
67
 
69
- def assert_mid_and_leaf_remain
70
- @mid.ancestry_path.should == %w{matt@t.co}
71
- @leaf.ancestry_path.should == %w{matt@t.co james@t.co}
72
- @mid.self_and_descendants.should =~ [@mid, @leaf]
73
- User.roots.should == [@mid]
74
- User.leaves.should == [@leaf]
68
+ def assert_mid_and_leaf_remain
69
+ ReferralHierarchy.find_all_by_ancestor_id(@root_id).should be_empty
70
+ ReferralHierarchy.find_all_by_descendant_id(@root_id).should be_empty
71
+ @mid.ancestry_path.should == %w{matt@t.co}
72
+ @leaf.ancestry_path.should == %w{matt@t.co james@t.co}
73
+ @mid.self_and_descendants.should =~ [@mid, @leaf]
74
+ User.roots.should == [@mid]
75
+ User.leaves.should == [@leaf]
76
+ end
77
+ end
75
78
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: closure_tree
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.0.4
4
+ version: 3.1.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-06-11 00:00:00.000000000 Z
12
+ date: 2012-07-09 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: activerecord
@@ -192,7 +192,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
192
192
  version: '0'
193
193
  segments:
194
194
  - 0
195
- hash: 1662601254141526016
195
+ hash: 1583374080415694998
196
196
  required_rubygems_version: !ruby/object:Gem::Requirement
197
197
  none: false
198
198
  requirements:
@@ -201,7 +201,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
201
201
  version: '0'
202
202
  segments:
203
203
  - 0
204
- hash: 1662601254141526016
204
+ hash: 1583374080415694998
205
205
  requirements: []
206
206
  rubyforge_project:
207
207
  rubygems_version: 1.8.21