closure_tree 3.10.1 → 3.10.2

Sign up to get free protection for your applications and to get access to all the features.
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