closure_tree 3.10.1 → 3.10.2

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
@@ -444,6 +444,16 @@ Parallelism is not tested with Rails 3.0.x nor 3.1.x due to this
444
444
 
445
445
  ## Change log
446
446
 
447
+ ### 3.10.2
448
+
449
+ * Prevent faulty SQL statement when ```#siblings``` is called on an unsaved records.
450
+ Resolves [issue 52](https://github.com/mceachen/closure_tree/pull/52). Perfect pull
451
+ request by [Gary Greyling](https://github.com/garygreyling).
452
+
453
+ * The ```.roots``` class method now correctly respects the ```:order``` option.
454
+ Resolves [issue 53](https://github.com/mceachen/closure_tree/issues/53).
455
+ Thanks for finding this, [Brendon Muir](https://github.com/brendon)!
456
+
447
457
  ### 3.10.1
448
458
 
449
459
  * Multipart constant names like "Admin::PageHierarchy" are now supported.
@@ -74,6 +74,10 @@ module ClosureTree
74
74
  order_option ? options.merge(:order => order_option) : options
75
75
  end
76
76
 
77
+ def scope_with_order(scope)
78
+ order_option ? scope.order(order_option) : scope
79
+ end
80
+
77
81
  def append_order(order_by)
78
82
  order_option ? "#{order_by}, #{order_option}" : order_by
79
83
  end
@@ -244,6 +244,7 @@ module ClosureTree
244
244
  end
245
245
 
246
246
  def without_self(scope)
247
+ return scope if self.new_record?
247
248
  scope.where(["#{quoted_table_name}.#{ct_base_class.primary_key} != ?", self])
248
249
  end
249
250
 
@@ -260,7 +261,7 @@ module ClosureTree
260
261
 
261
262
  module ClassMethods
262
263
  def roots
263
- where(parent_column_name => nil)
264
+ scope_with_order(where(parent_column_name => nil))
264
265
  end
265
266
 
266
267
  # Returns an arbitrary node that has no parents.
@@ -1,3 +1,3 @@
1
1
  module ClosureTree
2
- VERSION = "3.10.1" unless defined?(::ClosureTree::VERSION)
2
+ VERSION = "3.10.2" unless defined?(::ClosureTree::VERSION)
3
3
  end
data/spec/label_spec.rb CHANGED
@@ -38,10 +38,10 @@ def create_preorder_tree(suffix = "")
38
38
  root.self_and_descendants.each do |ea|
39
39
  ea.children.to_a.sort_by(&:name).each_with_index do |ea, idx|
40
40
  ea.order_value = idx
41
- ea.save!
41
+ ea.save!
42
+ end
42
43
  end
43
44
  end
44
- end
45
45
  end
46
46
 
47
47
  describe Label do
@@ -58,6 +58,22 @@ describe Label do
58
58
  end
59
59
  end
60
60
 
61
+ context "roots" do
62
+ before :each do
63
+ delete_all_labels
64
+ end
65
+ it "sorts alphabetically" do
66
+ expected = (0..10).to_a
67
+ expected.shuffle.each do |ea|
68
+ Label.create! do |l|
69
+ l.name = "root #{ea}"
70
+ l.sort_order = ea
71
+ end
72
+ end
73
+ Label.roots.collect { |ea| ea.sort_order }.should == expected
74
+ end
75
+ end
76
+
61
77
  context "Base Label class" do
62
78
  it "should find or create by path" do
63
79
  # class method:
@@ -346,6 +362,11 @@ describe Label do
346
362
  expected = ('a'..'r').to_a
347
363
  a.self_and_descendants_preordered.collect { |ea| ea.name }.should == expected
348
364
  Label.roots_and_descendants_preordered.collect { |ea| ea.name }.should == expected
365
+ # Let's create the second root by hand so we can explicitly set the sort order
366
+ Label.create! do |l|
367
+ l.name = "a1"
368
+ l.sort_order = a.sort_order + 1
369
+ end
349
370
  create_preorder_tree("1")
350
371
  # Should be no change:
351
372
  a.reload.self_and_descendants_preordered.collect { |ea| ea.name }.should == expected
data/spec/tag_spec.rb CHANGED
@@ -162,79 +162,86 @@ shared_examples_for "Tag (1)" do
162
162
  h.ancestry_path.should == %w(a b c d e f g h)
163
163
  end
164
164
 
165
- end
166
-
167
- context "paths" do
168
- before :each do
169
- @child = Tag.find_or_create_by_path(%w(grandparent parent child))
170
- @child.title = "Kid"
171
- @parent = @child.parent
172
- @parent.title = "Mom"
173
- @grandparent = @parent.parent
174
- @grandparent.title = "Nonnie"
175
- [@child, @parent, @grandparent].each { |ea| ea.save! }
165
+ context "roots" do
166
+ it "sorts alphabetically" do
167
+ expected = ("a".."z").to_a
168
+ expected.shuffle.each { |ea| Tag.create!(:name => ea) }
169
+ Tag.roots.collect { |ea| ea.name }.should == expected
170
+ end
176
171
  end
177
172
 
178
- it "should build ancestry path" do
179
- @child.ancestry_path.should == %w{grandparent parent child}
180
- @child.ancestry_path(:name).should == %w{grandparent parent child}
181
- @child.ancestry_path(:title).should == %w{Nonnie Mom Kid}
182
- end
173
+ context "paths" do
174
+ before :each do
175
+ @child = Tag.find_or_create_by_path(%w(grandparent parent child))
176
+ @child.title = "Kid"
177
+ @parent = @child.parent
178
+ @parent.title = "Mom"
179
+ @grandparent = @parent.parent
180
+ @grandparent.title = "Nonnie"
181
+ [@child, @parent, @grandparent].each { |ea| ea.save! }
182
+ end
183
183
 
184
- it "should find by path" do
185
- # class method:
186
- Tag.find_by_path(%w{grandparent parent child}).should == @child
187
- # instance method:
188
- @parent.find_by_path(%w{child}).should == @child
189
- @grandparent.find_by_path(%w{parent child}).should == @child
190
- @parent.find_by_path(%w{child larvae}).should be_nil
191
- end
184
+ it "should build ancestry path" do
185
+ @child.ancestry_path.should == %w{grandparent parent child}
186
+ @child.ancestry_path(:name).should == %w{grandparent parent child}
187
+ @child.ancestry_path(:title).should == %w{Nonnie Mom Kid}
188
+ end
192
189
 
193
- it "finds correctly rooted paths" do
194
- decoy = Tag.find_or_create_by_path %w(a b c d)
195
- b_d = Tag.find_or_create_by_path %w(b c d)
196
- Tag.find_by_path(%w(b c d)).should == b_d
197
- Tag.find_by_path(%w(c d)).should be_nil
198
- end
190
+ it "should find by path" do
191
+ # class method:
192
+ Tag.find_by_path(%w{grandparent parent child}).should == @child
193
+ # instance method:
194
+ @parent.find_by_path(%w{child}).should == @child
195
+ @grandparent.find_by_path(%w{parent child}).should == @child
196
+ @parent.find_by_path(%w{child larvae}).should be_nil
197
+ end
199
198
 
200
- it "find_by_path for 1 node" do
201
- b = Tag.find_or_create_by_path %w(a b)
202
- b2 = b.root.find_by_path(%w(b))
203
- b2.should == b
204
- end
199
+ it "finds correctly rooted paths" do
200
+ decoy = Tag.find_or_create_by_path %w(a b c d)
201
+ b_d = Tag.find_or_create_by_path %w(b c d)
202
+ Tag.find_by_path(%w(b c d)).should == b_d
203
+ Tag.find_by_path(%w(c d)).should be_nil
204
+ end
205
205
 
206
- it "find_by_path for 2 nodes" do
207
- c = Tag.find_or_create_by_path %w(a b c)
208
- c.root.find_by_path(%w(b c)).should == c
209
- c.root.find_by_path(%w(a c)).should be_nil
210
- c.root.find_by_path(%w(c)).should be_nil
211
- end
206
+ it "find_by_path for 1 node" do
207
+ b = Tag.find_or_create_by_path %w(a b)
208
+ b2 = b.root.find_by_path(%w(b))
209
+ b2.should == b
210
+ end
212
211
 
213
- it "find_by_path for 3 nodes" do
214
- d = Tag.find_or_create_by_path %w(a b c d)
215
- d.root.find_by_path(%w(b c d)).should == d
216
- Tag.find_by_path(%w(a b c d)).should == d
217
- Tag.find_by_path(%w(d)).should be_nil
218
- end
212
+ it "find_by_path for 2 nodes" do
213
+ c = Tag.find_or_create_by_path %w(a b c)
214
+ c.root.find_by_path(%w(b c)).should == c
215
+ c.root.find_by_path(%w(a c)).should be_nil
216
+ c.root.find_by_path(%w(c)).should be_nil
217
+ end
219
218
 
220
- it "should return nil for missing nodes" do
221
- Tag.find_by_path(%w{missing}).should be_nil
222
- Tag.find_by_path(%w{grandparent missing}).should be_nil
223
- Tag.find_by_path(%w{grandparent parent missing}).should be_nil
224
- Tag.find_by_path(%w{grandparent parent missing child}).should be_nil
225
- end
219
+ it "find_by_path for 3 nodes" do
220
+ d = Tag.find_or_create_by_path %w(a b c d)
221
+ d.root.find_by_path(%w(b c d)).should == d
222
+ Tag.find_by_path(%w(a b c d)).should == d
223
+ Tag.find_by_path(%w(d)).should be_nil
224
+ end
225
+
226
+ it "should return nil for missing nodes" do
227
+ Tag.find_by_path(%w{missing}).should be_nil
228
+ Tag.find_by_path(%w{grandparent missing}).should be_nil
229
+ Tag.find_by_path(%w{grandparent parent missing}).should be_nil
230
+ Tag.find_by_path(%w{grandparent parent missing child}).should be_nil
231
+ end
226
232
 
227
- it "should find or create by path" do
228
- # class method:
229
- grandparent = Tag.find_or_create_by_path(%w{grandparent})
230
- grandparent.should == @grandparent
231
- child = Tag.find_or_create_by_path(%w{grandparent parent child})
232
- child.should == @child
233
- Tag.find_or_create_by_path(%w{events anniversary}).ancestry_path.should == %w{events anniversary}
234
- a = Tag.find_or_create_by_path(%w{a})
235
- a.ancestry_path.should == %w{a}
236
- # instance method:
237
- a.find_or_create_by_path(%w{b c}).ancestry_path.should == %w{a b c}
233
+ it "should find or create by path" do
234
+ # class method:
235
+ grandparent = Tag.find_or_create_by_path(%w{grandparent})
236
+ grandparent.should == @grandparent
237
+ child = Tag.find_or_create_by_path(%w{grandparent parent child})
238
+ child.should == @child
239
+ Tag.find_or_create_by_path(%w{events anniversary}).ancestry_path.should == %w{events anniversary}
240
+ a = Tag.find_or_create_by_path(%w{a})
241
+ a.ancestry_path.should == %w{a}
242
+ # instance method:
243
+ a.find_or_create_by_path(%w{b c}).ancestry_path.should == %w{a b c}
244
+ end
238
245
  end
239
246
  end
240
247
  end
@@ -408,7 +415,6 @@ shared_examples_for "Tag (2)" do
408
415
  end
409
416
  end
410
417
 
411
-
412
418
  def validate_city_tag city
413
419
  tags(:california).children.include?(city).should_not be_nil
414
420
  city.ancestors.should == [tags(:california), tags(:united_states), tags(:places)]
data/spec/user_spec.rb CHANGED
@@ -31,7 +31,6 @@ describe "empty db" do
31
31
  end
32
32
  end
33
33
 
34
-
35
34
  context "3 User collection.create db" do
36
35
  before :each do
37
36
  @root = User.create! :email => "poppy@t.co"
@@ -126,6 +125,18 @@ describe "empty db" do
126
125
  b1.siblings.should =~ [b2, b3]
127
126
  end
128
127
 
128
+ context "when a user is not yet saved" do
129
+ it "supports siblings" do
130
+ User.order_option.should be_nil
131
+ a = User.create(:email => "a")
132
+ b1 = a.children.new(:email => "b1")
133
+ b2 = a.children.create(:email => "b2")
134
+ b3 = a.children.create(:email => "b3")
135
+ a.siblings.should be_empty
136
+ b1.siblings.should =~ [b2, b3]
137
+ end
138
+ end
139
+
129
140
  it "properly nullifies descendents" do
130
141
  c = User.find_or_create_by_path %w(a b c)
131
142
  b = c.parent
@@ -133,4 +144,16 @@ describe "empty db" do
133
144
  b.reload.should be_root
134
145
  b.child_ids.should == [c.id]
135
146
  end
147
+
148
+ context "roots" do
149
+ it "works on models without ordering" do
150
+ expected = ("a".."z").to_a
151
+ expected.shuffle.each do |ea|
152
+ User.create! do |u|
153
+ u.email = ea
154
+ end
155
+ end
156
+ User.roots.collect { |ea| ea.email }.sort.should == expected
157
+ end
158
+ end
136
159
  end
metadata CHANGED
@@ -1,7 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: closure_tree
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.10.1
4
+ hash: 43
5
+ prerelease:
6
+ segments:
7
+ - 3
8
+ - 10
9
+ - 2
10
+ version: 3.10.2
5
11
  platform: ruby
6
12
  authors:
7
13
  - Matthew McEachen
@@ -9,110 +15,180 @@ autorequire:
9
15
  bindir: bin
10
16
  cert_chain: []
11
17
 
12
- date: 2013-03-23 00:00:00 Z
18
+ date: 2013-04-16 00:00:00 -07:00
19
+ default_executable:
13
20
  dependencies:
14
21
  - !ruby/object:Gem::Dependency
15
- name: activerecord
16
- type: :runtime
17
22
  requirement: &id001 !ruby/object:Gem::Requirement
23
+ none: false
18
24
  requirements:
19
25
  - - ">="
20
26
  - !ruby/object:Gem::Version
27
+ hash: 7
28
+ segments:
29
+ - 3
30
+ - 0
31
+ - 0
21
32
  version: 3.0.0
33
+ type: :runtime
34
+ name: activerecord
22
35
  version_requirements: *id001
23
36
  prerelease: false
24
37
  - !ruby/object:Gem::Dependency
25
- name: with_advisory_lock
26
- type: :runtime
27
38
  requirement: &id002 !ruby/object:Gem::Requirement
39
+ none: false
28
40
  requirements:
29
41
  - - ">="
30
42
  - !ruby/object:Gem::Version
43
+ hash: 19
44
+ segments:
45
+ - 0
46
+ - 0
47
+ - 6
31
48
  version: 0.0.6
49
+ type: :runtime
50
+ name: with_advisory_lock
32
51
  version_requirements: *id002
33
52
  prerelease: false
34
53
  - !ruby/object:Gem::Dependency
35
- name: rake
36
- type: :development
37
54
  requirement: &id003 !ruby/object:Gem::Requirement
55
+ none: false
38
56
  requirements:
39
- - &id004
40
- - ">="
57
+ - - ">="
41
58
  - !ruby/object:Gem::Version
59
+ hash: 3
60
+ segments:
61
+ - 0
42
62
  version: "0"
63
+ type: :development
64
+ name: rake
43
65
  version_requirements: *id003
44
66
  prerelease: false
45
67
  - !ruby/object:Gem::Dependency
46
- name: yard
68
+ requirement: &id004 !ruby/object:Gem::Requirement
69
+ none: false
70
+ requirements:
71
+ - - ">="
72
+ - !ruby/object:Gem::Version
73
+ hash: 3
74
+ segments:
75
+ - 0
76
+ version: "0"
47
77
  type: :development
78
+ name: yard
79
+ version_requirements: *id004
80
+ prerelease: false
81
+ - !ruby/object:Gem::Dependency
48
82
  requirement: &id005 !ruby/object:Gem::Requirement
83
+ none: false
49
84
  requirements:
50
- - *id004
85
+ - - ">="
86
+ - !ruby/object:Gem::Version
87
+ hash: 3
88
+ segments:
89
+ - 0
90
+ version: "0"
91
+ type: :development
92
+ name: rspec
51
93
  version_requirements: *id005
52
94
  prerelease: false
53
95
  - !ruby/object:Gem::Dependency
54
- name: rspec
55
- type: :development
56
96
  requirement: &id006 !ruby/object:Gem::Requirement
97
+ none: false
57
98
  requirements:
58
- - *id004
99
+ - - ">="
100
+ - !ruby/object:Gem::Version
101
+ hash: 3
102
+ segments:
103
+ - 0
104
+ version: "0"
105
+ type: :development
106
+ name: rails
59
107
  version_requirements: *id006
60
108
  prerelease: false
61
109
  - !ruby/object:Gem::Dependency
62
- name: rails
63
- type: :development
64
110
  requirement: &id007 !ruby/object:Gem::Requirement
111
+ none: false
65
112
  requirements:
66
- - *id004
113
+ - - ">="
114
+ - !ruby/object:Gem::Version
115
+ hash: 3
116
+ segments:
117
+ - 0
118
+ version: "0"
119
+ type: :development
120
+ name: rspec-rails
67
121
  version_requirements: *id007
68
122
  prerelease: false
69
123
  - !ruby/object:Gem::Dependency
70
- name: rspec-rails
71
- type: :development
72
124
  requirement: &id008 !ruby/object:Gem::Requirement
125
+ none: false
73
126
  requirements:
74
- - *id004
127
+ - - ">="
128
+ - !ruby/object:Gem::Version
129
+ hash: 3
130
+ segments:
131
+ - 0
132
+ version: "0"
133
+ type: :development
134
+ name: mysql2
75
135
  version_requirements: *id008
76
136
  prerelease: false
77
137
  - !ruby/object:Gem::Dependency
78
- name: mysql2
79
- type: :development
80
138
  requirement: &id009 !ruby/object:Gem::Requirement
139
+ none: false
81
140
  requirements:
82
- - *id004
141
+ - - ">="
142
+ - !ruby/object:Gem::Version
143
+ hash: 3
144
+ segments:
145
+ - 0
146
+ version: "0"
147
+ type: :development
148
+ name: pg
83
149
  version_requirements: *id009
84
150
  prerelease: false
85
151
  - !ruby/object:Gem::Dependency
86
- name: pg
87
- type: :development
88
152
  requirement: &id010 !ruby/object:Gem::Requirement
153
+ none: false
89
154
  requirements:
90
- - *id004
155
+ - - ">="
156
+ - !ruby/object:Gem::Version
157
+ hash: 3
158
+ segments:
159
+ - 0
160
+ version: "0"
161
+ type: :development
162
+ name: sqlite3
91
163
  version_requirements: *id010
92
164
  prerelease: false
93
165
  - !ruby/object:Gem::Dependency
94
- name: sqlite3
95
- type: :development
96
166
  requirement: &id011 !ruby/object:Gem::Requirement
167
+ none: false
97
168
  requirements:
98
- - *id004
169
+ - - ">="
170
+ - !ruby/object:Gem::Version
171
+ hash: 3
172
+ segments:
173
+ - 0
174
+ version: "0"
175
+ type: :development
176
+ name: uuidtools
99
177
  version_requirements: *id011
100
178
  prerelease: false
101
179
  - !ruby/object:Gem::Dependency
102
- name: uuidtools
103
- type: :development
104
180
  requirement: &id012 !ruby/object:Gem::Requirement
181
+ none: false
105
182
  requirements:
106
- - *id004
107
- version_requirements: *id012
108
- prerelease: false
109
- - !ruby/object:Gem::Dependency
110
- name: strong_parameters
183
+ - - ">="
184
+ - !ruby/object:Gem::Version
185
+ hash: 3
186
+ segments:
187
+ - 0
188
+ version: "0"
111
189
  type: :development
112
- requirement: &id013 !ruby/object:Gem::Requirement
113
- requirements:
114
- - *id004
115
- version_requirements: *id013
190
+ name: strong_parameters
191
+ version_requirements: *id012
116
192
  prerelease: false
117
193
  description: Easily and efficiently make your ActiveRecord model support hierarchies
118
194
  email:
@@ -149,28 +225,39 @@ files:
149
225
  - spec/support/models.rb
150
226
  - spec/tag_spec.rb
151
227
  - spec/user_spec.rb
228
+ has_rdoc: true
152
229
  homepage: http://matthew.mceachen.us/closure_tree
153
230
  licenses: []
154
231
 
155
- metadata: {}
156
-
157
232
  post_install_message:
158
233
  rdoc_options: []
159
234
 
160
235
  require_paths:
161
236
  - lib
162
237
  required_ruby_version: !ruby/object:Gem::Requirement
238
+ none: false
163
239
  requirements:
164
- - *id004
240
+ - - ">="
241
+ - !ruby/object:Gem::Version
242
+ hash: 3
243
+ segments:
244
+ - 0
245
+ version: "0"
165
246
  required_rubygems_version: !ruby/object:Gem::Requirement
247
+ none: false
166
248
  requirements:
167
- - *id004
249
+ - - ">="
250
+ - !ruby/object:Gem::Version
251
+ hash: 3
252
+ segments:
253
+ - 0
254
+ version: "0"
168
255
  requirements: []
169
256
 
170
257
  rubyforge_project:
171
- rubygems_version: 2.0.0
258
+ rubygems_version: 1.6.2
172
259
  signing_key:
173
- specification_version: 4
260
+ specification_version: 3
174
261
  summary: Easily and efficiently make your ActiveRecord model support hierarchies
175
262
  test_files:
176
263
  - spec/cuisine_type_spec.rb
@@ -187,4 +274,3 @@ test_files:
187
274
  - spec/support/models.rb
188
275
  - spec/tag_spec.rb
189
276
  - spec/user_spec.rb
190
- has_rdoc:
checksums.yaml DELETED
@@ -1,7 +0,0 @@
1
- ---
2
- SHA1:
3
- metadata.gz: 50404d7f26719cd30625a177d0c7fbc9c4396843
4
- data.tar.gz: 38ae281b5a8f92005839a0c2f08a4e4774881001
5
- SHA512:
6
- metadata.gz: c862247bb1c73a3e98bd531a51a49274d7478453ee77777927fdad9a88502aa5f733183690c538e49a37d307bbb868d726239189671eac6782ac0b618966a0dc
7
- data.tar.gz: 6b533b01ff64e084af4c41e669d0847dc98f8464634b78e365ab2cc6d4245e7f4a0991b65701ca869ff67e4e3151ba30283b85d6f99553bbff9bfd345439cc5c