closure_tree 3.0.4 → 3.1.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 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