public
Fork of collectiveidea/awesome_nested_set
Description: An awesome replacement for acts_as_nested_set and better_nested_set.
Clone URL: git://github.com/tokumine/awesome_nested_set.git
added named_scope from edge rails and re-wrote finders to use scopes. 
Updated docs
brandon (author)
Sat May 17 12:37:07 -0700 2008
commit  8b20635496c373d8d3f846605c17d588ec7e82bf
tree    70b286dadededc7fea64a6e3783029043c96a180
parent  de50fd4c8d61e23a467b6190ab8535ebfbd5efa5
...
1
2
3
 
 
 
 
 
4
5
6
...
12
13
14
15
16
17
 
18
19
20
21
 
22
23
24
...
35
36
37
38
 
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
 
 
111
112
113
114
115
 
 
 
 
116
117
118
...
124
125
126
127
 
128
...
1
2
 
3
4
5
6
7
8
9
10
...
16
17
18
 
 
 
19
20
 
 
 
21
22
23
24
...
35
36
37
 
38
39
40
41
42
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
43
44
45
46
47
 
 
48
49
50
51
52
53
54
...
60
61
62
 
63
64
0
@@ -1,6 +1,10 @@
0
 = AwesomeNestedSet
0
 
0
-Awesome Nested Set is a complete replacement for acts_as_nested_set and betternestedset, but awesomer.
0
+Awesome Nested Set is an implementation of the nested set pattern for ActiveRecord models. It is replacement for acts_as_nested_set and BetterNestedSet, but awesomer.
0
+
0
+== What makes this so awesome?
0
+
0
+This is a new implementation of nested set based off of BetterNestedSet that fixes some bugs, removes tons of duplication, adds a few useful methods, adds STI support and adds 2 very helpful view helpers for select boxes.
0
 
0
 == Installation
0
 
0
@@ -12,13 +16,9 @@ If you are not on edge rails:
0
 
0
   git clone git://github.com/collectiveidea/awesome_nested_set.git vendor/plugins/awesome_nested_set
0
 
0
-== What makes this so awesome?
0
-
0
-This is a new implementation of nested set based off of better nested set. It fixes some bugs, removes tons of duplication, adds a few useful methods, adds STI support and adds 2 very helpful view helpers for select boxes.
0
+== Usage
0
 
0
-== ActiveRecord
0
-
0
-Create a migration like:
0
+To make use of awesome_nested_set, your model needs to have 3 fields: lft, rgt, and parent_id:
0
 
0
   class CreateCategories < ActiveRecord::Migration
0
     def self.up
0
@@ -35,84 +35,20 @@ Create a migration like:
0
     end
0
   end
0
 
0
-Then create a model like:
0
+Enable the nested set functionality by declaring acts_as_ferret on your model
0
 
0
   class Category < ActiveRecord::Base
0
     acts_as_nested_set
0
   end
0
-
0
-Methods names are aligned on Tree's ones as much as possible, to make replacment from one
0
-by another easier, except for the creation:
0
-
0
-in acts_as_tree:
0
-
0
- item.children.create(:name => "child1")
0
-
0
-in acts_as_nested_set:
0
-
0
- # adds a new item at the "end" of the tree, i.e. with child.left = max(tree.right)</tt>1
0
- child = MyClass.new(:name => "child1")
0
- child.save
0
- # now move the item to its right place
0
- child.move_to_child_of my_item
0
-
0
-You can use:
0
-* move_to_child_of
0
-* move_to_right_of
0
-* move_to_left_of
0
-and pass them an id or an object.
0
-
0
-== Class Methods
0
-
0
-* <tt>root</tt> - Returns the first root
0
-* <tt>roots</tt> - root items, in case of multiple roots (the ones that have a nil parent)
0
-* <tt>valid?</tt> -
0
-* <tt>left_and_rights_valid?</tt> -
0
-* <tt>def no_duplicates_for_column?</tt> - pass in quoted_left_column_name or quoted_right_column_name
0
-* <tt>all_roots_valid?</tt> - Wrapper for each_root_valid? that can deal with scope.
0
-* <tt>each_root_valid?</tt> -
0
-* <tt>rebuild!</tt> - Rebuilds the left & rights if unset or invalid. Also very useful for converting from acts_as_tree.
0
-
0
-== Instance Methods
0
-
0
-* <tt>parent_id</tt> -
0
-* <tt>left</tt> -
0
-* <tt>right</tt> -
0
-* <tt>root?</tt> - Returns true if this is a root node.
0
-* <tt>child?</tt> - Returns true is this is a child node
0
-* <tt><=>(x)</tt> - order by left column
0
-* <tt>add_child( child )</tt> - Deprecated, will be removed in next versions
0
-* <tt>root</tt> - Returns root
0
-* <tt>parent</tt> - Returns the parent
0
-* <tt>self_and_ancestors(multiplicity = :all, *args)</tt> - Returns the array of all parents and self
0
-* <tt>ancestors(*args)</tt> - Returns an array of all parents
0
-* <tt>self_and_siblings(multiplicity = :all, *args)</tt> - Returns the array of all children of the parent, including self
0
-* <tt>siblings(*args)</tt> - Returns the array of all children of the parent, except self
0
-* <tt>level</tt> Returns the level of this object in the tree - root level is 0
0
-* <tt>children_count</tt> - Returns the number of nested children of this object.
0
-* <tt>has_children?</tt>
0
-* <tt>self_and_descendants(multiplicity = :all, *args)</tt> - Returns a set of itself and all of its nested children
0
-* <tt>descendants(*args)</tt> - Returns a set of all of its children and nested children
0
-* <tt>children(multiplicity = :all, *args)</tt> - Returns a set of only this entry's immediate children
0
-* <tt>is_descendant_of?(other)</tt>
0
-* <tt>is_or_is_descendant_of?(other)</tt>
0
-* <tt>is_ancestor_of?(other)</tt>
0
-* <tt>is_or_is_ancestor_of?(other)</tt>
0
-* <tt>is_same_scope?(other)</tt>
0
-* <tt>left_sibling</tt> - Find the first sibling to the right
0
-* <tt>right_sibling</tt> - Find the first sibling to the right
0
-* <tt>move_left</tt> - Shorthand method for finding the left sibling and moving to the left of it.
0
-* <tt>move_right</tt> - Shorthand method for finding the right sibling and moving to the right of it.
0
-* <tt>move_to_left_of(node)</tt> - Move the node to the left of another node (you can pass id only)
0
-* <tt>move_to_right_of(node)</tt> - Move the node to the left of another node (you can pass id only)
0
-* <tt>move_to_child_of(node)</tt> - Move the node to the child of another node (you can pass id only)
0
-* <tt>move_possible?(target)</tt>
0
-* <tt>to_text</tt>
0
+
0
+Run `rake rdoc` to generate the API docs and see CollectiveIdea::Acts::NestedSet::SingletonMethods for more info.
0
 
0
 == View Helpers
0
 
0
-* <tt>nested_set_options_for_select</tt> - returns an array of objects suitable for select helpers
0
-* <tt>nested_set_options_for_select_without_impossible_moves</tt> - similar to nested_set_options_for_select, but contains only items that are possible to move to
0
+* <tt>#nested_set_options_for_select</tt> - returns an array of objects suitable for select helpers
0
+* <tt>#nested_set_options_for_select_without_impossible_moves</tt> - similar to nested_set_options_for_select, but contains only items that are possible to move to
0
+
0
+See CollectiveIdea::Acts::NestedSet::Helper for more information about the helpers.
0
 
0
 == References
0
 
0
@@ -124,4 +60,4 @@ You can learn more about nested sets at:
0
   http://opensource.symetrie.com/trac/better_nested_set/
0
 
0
 
0
-Copyright (c) 2008 Collective Idea, released under the MIT license
0
+Copyright (c) 2008 Collective Idea, released under the MIT license
0
\ No newline at end of file
...
17
18
19
20
 
21
22
...
17
18
19
 
20
21
22
0
@@ -17,6 +17,6 @@ Rake::RDocTask.new(:rdoc) do |rdoc|
0
   rdoc.rdoc_dir = 'rdoc'
0
   rdoc.title = 'AwesomeNestedSet'
0
   rdoc.options << '--line-numbers' << '--inline-source'
0
- rdoc.rdoc_files.include('README')
0
+ rdoc.rdoc_files.include('README.rdoc')
0
   rdoc.rdoc_files.include('lib/**/*.rb')
0
 end
...
 
 
 
 
 
 
 
1
2
 
3
4
5
6
7
8
9
 
10
11
...
1
2
3
4
5
6
7
8
 
9
10
11
12
13
14
15
 
16
17
18
0
@@ -1,10 +1,17 @@
0
+unless defined? ActiveRecord::NamedScope
0
+ require 'awesome_nested_set/named_scope'
0
+ ActiveRecord::Base.class_eval do
0
+ include CollectiveIdea::NamedScope
0
+ end
0
+end
0
+
0
 require 'awesome_nested_set'
0
-require 'awesome_nested_set_helper'
0
+require 'awesome_nested_set/helper'
0
 
0
 ActiveRecord::Base.class_eval do
0
   include CollectiveIdea::Acts::NestedSet
0
 end
0
 
0
 ActionView::Base.class_eval do
0
- include CollectiveIdea::Acts::NestedSetHelper
0
+ include CollectiveIdea::Acts::NestedSet::Helper
0
 end
0
\ No newline at end of file
...
5
6
7
8
9
10
11
12
13
14
15
16
17
18
...
22
23
24
25
 
 
26
27
28
...
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
 
 
 
 
65
66
67
...
73
74
75
 
 
 
 
76
77
78
...
89
90
91
92
93
 
 
94
95
96
...
109
110
111
112
 
 
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
 
129
130
131
132
133
134
135
 
 
 
136
137
138
...
155
156
157
158
 
159
160
161
...
214
215
216
217
218
 
 
219
220
221
...
249
250
251
 
 
 
 
252
 
 
253
 
254
255
256
257
 
258
259
260
261
 
262
263
264
...
270
271
272
273
 
274
275
276
...
322
323
324
325
 
326
327
328
 
329
330
 
331
332
333
334
335
336
337
 
 
338
339
340
341
342
 
 
343
344
345
346
347
348
349
350
351
352
353
354
 
 
355
356
357
358
359
 
 
360
361
362
...
365
366
367
368
369
370
 
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
 
 
 
391
392
393
394
395
 
 
396
397
398
399
400
401
402
403
404
 
 
405
406
407
408
 
409
410
411
412
 
413
414
415
416
 
417
418
419
420
 
421
422
423
424
 
 
 
 
425
426
427
428
429
430
431
432
433
434
435
436
437
438
 
 
 
 
 
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
 
 
 
 
 
454
455
456
457
458
 
459
460
461
462
463
 
464
465
466
...
482
483
484
485
 
486
487
488
...
496
497
498
499
500
501
502
 
 
503
504
505
506
507
508
509
510
 
 
 
 
 
511
512
 
513
514
 
515
516
 
517
518
519
 
520
521
522
...
528
529
530
531
532
533
534
535
536
537
538
 
 
 
 
 
 
539
540
541
...
5
6
7
 
 
 
 
 
 
 
 
8
9
10
...
14
15
16
 
17
18
19
20
21
...
28
29
30
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
31
32
33
34
35
36
37
...
43
44
45
46
47
48
49
50
51
52
...
63
64
65
 
 
66
67
68
69
70
...
83
84
85
 
86
87
88
89
90
91
92
93
 
 
 
 
 
 
 
94
95
 
96
97
98
99
100
 
 
 
101
102
103
104
105
106
...
123
124
125
 
126
127
128
129
...
182
183
184
 
 
185
186
187
188
189
...
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
...
247
248
249
 
250
251
252
253
...
299
300
301
 
302
303
304
 
305
306
 
307
308
309
310
 
 
 
 
311
312
313
314
315
 
 
316
317
318
319
320
 
 
 
 
 
 
 
 
 
321
322
323
324
325
 
 
326
327
328
329
330
...
333
334
335
 
 
 
336
337
338
339
 
 
 
 
 
 
 
 
 
 
340
 
 
 
 
 
 
341
342
343
344
345
346
 
 
347
348
349
350
351
 
 
 
 
 
 
352
353
354
355
356
 
357
358
359
360
 
361
362
363
364
 
365
366
367
368
 
369
370
371
 
 
372
373
374
375
376
377
378
379
 
 
 
 
 
 
 
 
 
 
380
381
382
383
384
385
386
387
388
 
 
 
 
 
 
 
 
 
 
 
389
390
391
392
393
394
395
396
397
 
398
399
400
401
402
 
403
404
405
406
...
422
423
424
 
425
426
427
428
...
436
437
438
 
 
 
 
439
440
441
442
 
 
 
 
 
 
443
444
445
446
447
448
 
449
450
 
451
452
 
453
454
455
 
456
457
458
459
...
465
466
467
 
 
 
 
 
 
 
 
468
469
470
471
472
473
474
475
476
0
@@ -5,14 +5,6 @@ module CollectiveIdea
0
         base.extend(SingletonMethods)
0
       end
0
 
0
- # better_nested_set ehances the core nested_set tree functionality provided in ruby_on_rails.
0
- #
0
- # awesome_nested_set goes further, first with a major refactoring
0
- # Features:
0
- # * almost API-compatible (some broken bits had to be changed)
0
- # * allow it to work with a tree that spans across STI classes
0
- # * removed roots instance method, which was an impossible method.
0
- #
0
       # This acts provides Nested Set functionality. Nested Set is a smart way to implement
0
       # an _ordered_ tree, with the added feature that you can select the children and all of their
0
       # descendants with a single query. The drawback is that insertion or move need some complex
0
@@ -22,7 +14,8 @@ module CollectiveIdea
0
       # commercial categories) or an efficient way of querying big trees (threaded posts).
0
       #
0
       # == API
0
- # Methods names are aligned on Tree's ones as much as possible, to make replacment from one
0
+ #
0
+ # Methods names are aligned with acts_as_tree as much as possible, to make replacment from one
0
       # by another easier, except for the creation:
0
       #
0
       # in acts_as_tree:
0
@@ -35,33 +28,10 @@ module CollectiveIdea
0
       # # now move the item to its right place
0
       # child.move_to_child_of my_item
0
       #
0
- # You can use:
0
- # * move_to_child_of
0
- # * move_to_right_of
0
- # * move_to_left_of
0
- # and pass them an id or an object.
0
- #
0
- # Other methods added by this mixin are:
0
- # * +root+ - root item of the tree (the one that has a nil parent; should have left_column = 1 too)
0
- # * +roots+ - root items, in case of multiple roots (the ones that have a nil parent)
0
- # * +level+ - number indicating the level, a root being level 0
0
- # * +ancestors+ - array of all parents, with root as first item
0
- # * +self_and_ancestors+ - array of all parents and self
0
- # * +siblings+ - array of all siblings, that are the items sharing the same parent and level
0
- # * +self_and_siblings+ - array of itself and all siblings
0
- # * +children_count+ - count of all immediate children
0
- # * +children+ - array of all immediate childrens
0
- # * +all_children+ - array of all children and nested children
0
- # * +full_set+ - array of itself and all children and nested children
0
- #
0
- # These should not be useful, except if you want to write direct SQL:
0
- # * +left_column_name+ - name of the left column passed on the declaration line
0
- # * +right_column_name+ - name of the right column passed on the declaration line
0
- # * +parent_column_name+ - name of the parent column passed on the declaration line
0
- #
0
- # recommandations:
0
- # Don't name your left and right columns 'left' and 'right': these names are reserved on most of dbs.
0
- # Usage is to name them 'lft' and 'rgt' for instance.
0
+ # You can pass an id or an object to:
0
+ # * <tt>#move_to_child_of</tt>
0
+ # * <tt>#move_to_right_of</tt>
0
+ # * <tt>#move_to_left_of</tt>
0
       #
0
       module SingletonMethods
0
         # Configuration options are:
0
@@ -73,6 +43,10 @@ module CollectiveIdea
0
         # (if that hasn't been already) and use that as the foreign key restriction. It's also possible
0
         # to give it an entire string that is interpolated if you need a tighter scope than just a foreign key.
0
         # Example: <tt>acts_as_nested_set :scope => 'todo_list_id = #{todo_list_id} AND completed = 0'</tt>
0
+ #
0
+ # See CollectiveIdea::Acts::NestedSet::ClassMethods for a list of class methods and
0
+ # CollectiveIdea::Acts::NestedSet::InstanceMethods for a list of instance methods added
0
+ # to acts_as_nested_set models
0
         def acts_as_nested_set(options = {})
0
           options = {
0
             :parent_column => 'parent_id',
0
@@ -89,8 +63,8 @@ module CollectiveIdea
0
           
0
           include InstanceMethods
0
           include Comparable
0
- include Helpers
0
- extend Helpers
0
+ include Columns
0
+ extend Columns
0
           extend ClassMethods
0
 
0
           # no bulk assignment
0
@@ -109,30 +83,24 @@ module CollectiveIdea
0
               end
0
             end_eval
0
           end
0
-
0
+
0
+ named_scope :roots, :conditions => {parent_column_name => nil}, :order => left_column_name
0
         end
0
         
0
       end
0
       
0
       module ClassMethods
0
         
0
- def roots(multiplicity = :all, *args)
0
- with_scope(:find => {:conditions => {parent_column_name => nil},
0
- :order => left_column_name }) do
0
- find(multiplicity, *args)
0
- end
0
- end
0
-
0
         # Returns the first root
0
         def root
0
- roots(:first)
0
+ roots.find(:first)
0
         end
0
         
0
         def valid?
0
           left_and_rights_valid? &&
0
- no_duplicates_for_column?(quoted_left_column_name) &&
0
- no_duplicates_for_column?(quoted_right_column_name) &&
0
- all_roots_valid?
0
+ no_duplicates_for_column?(quoted_left_column_name) &&
0
+ no_duplicates_for_column?(quoted_right_column_name) &&
0
+ all_roots_valid?
0
         end
0
         
0
         def left_and_rights_valid?
0
@@ -155,7 +123,7 @@ module CollectiveIdea
0
         
0
         # pass in quoted_left_column_name or quoted_right_column_name
0
         def no_duplicates_for_column?(column)
0
- scope_string = "#{quoted_scope_column_name+', ' if acts_as_nested_set_options[:scope]}"
0
+ scope_string = acts_as_nested_set_options[:scope] ? '' : "#{quoted_scope_column_name}, "
0
           # No duplicates
0
           find(:first,
0
             :select => "#{scope_string}#{column}, COUNT(#{column})",
0
@@ -214,8 +182,8 @@ module CollectiveIdea
0
         end
0
       end
0
       
0
- # Mixed into both classes and instances
0
- module Helpers
0
+ # Mixed into both classes and instances to provide easy access to the column names
0
+ module Columns
0
         def left_column_name
0
           acts_as_nested_set_options[:left_column]
0
         end
0
@@ -249,16 +217,25 @@ module CollectiveIdea
0
         end
0
       end
0
 
0
+ # Any instance method that returns a collection makes use of Rails 2.1's named_scope (which is bundled for Rails 2.0), so it can be treated as a finder.
0
+ #
0
+ # category.self_and_descendants.count
0
+ # category.ancestors.find(:all, :conditions => "name like '%foo%'")
0
       module InstanceMethods
0
+ # alias ActiveRecord::Base::Scope so we don't always have to refer to it with the long name
0
+ Scope = ActiveRecord::Base::Scope
0
         
0
+ # Value of the parent column
0
         def parent_id
0
           self[parent_column_name]
0
         end
0
         
0
+ # Value of the left column
0
         def left
0
           self[left_column_name]
0
         end
0
         
0
+ # Value of the right column
0
         def right
0
           self[right_column_name]
0
         end
0
@@ -270,7 +247,7 @@ module CollectiveIdea
0
 
0
         # Returns true is this is a child node
0
         def child?
0
- !parent_id.nil? && left > 1
0
+ !parent_id.nil?
0
         end
0
 
0
         # order by left column
0
@@ -322,41 +299,32 @@ module CollectiveIdea
0
 
0
         # Returns root
0
         def root
0
- self_and_ancestors(:first)
0
+ self_and_ancestors.find(:first)
0
         end
0
 
0
- # Returns the parent
0
+ # Returns the immediate parent
0
         def parent
0
- self.class.base_class.find_by_id(parent_id) if parent_id
0
+ nested_set_scope.find_by_id(parent_id) if parent_id
0
         end
0
 
0
         # Returns the array of all parents and self
0
- def self_and_ancestors(multiplicity = :all, *args)
0
- with_nested_set_scope do
0
- with_find_scope(:conditions => "#{left_column_name} <= #{left} AND #{right_column_name} >= #{right}") { self.class.base_class.find(multiplicity, *args) }
0
- end
0
+ def self_and_ancestors
0
+ Scope.new(nested_set_scope, :conditions => "#{left_column_name} <= #{left} AND #{right_column_name} >= #{right}")
0
         end
0
 
0
         # Returns an array of all parents
0
- def ancestors(*args)
0
- without_self { self_and_ancestors(*args) }
0
+ def ancestors
0
+ without_self self_and_ancestors
0
         end
0
 
0
         # Returns the array of all children of the parent, including self
0
- def self_and_siblings(multiplicity = :all, *args)
0
- with_nested_set_scope do
0
- scope = if parent_id.nil?
0
- {self.class.base_class.primary_key => self}
0
- else
0
- {parent_column_name => parent_id}
0
- end
0
- with_find_scope(:conditions => scope) { self.class.base_class.find(multiplicity, *args) }
0
- end
0
+ def self_and_siblings
0
+ parent.children
0
         end
0
 
0
         # Returns the array of all children of the parent, except self
0
- def siblings(*args)
0
- without_self { self_and_siblings(*args) }
0
+ def siblings
0
+ without_self self_and_siblings
0
         end
0
 
0
         # Returns the level of this object in the tree
0
@@ -365,102 +333,74 @@ module CollectiveIdea
0
           if parent_id.nil?
0
             0
0
           else
0
- with_nested_set_scope do
0
- self.class.base_class.count(:conditions => "(#{left_column_name} < #{left} AND #{right_column_name} > #{right})")
0
- end
0
+ nested_set_scope.count(:conditions => "(#{left_column_name} < #{left} AND #{right_column_name} > #{right})")
0
           end
0
         end
0
 
0
- # Returns the number of nested children of this object.
0
- # FIXME: rename to descendants.count
0
- def children_count
0
- (right - left - 1) / 2
0
- end
0
-
0
- def has_children?
0
- !children_count.zero?
0
- end
0
-
0
         # Returns a set of itself and all of its nested children
0
- def self_and_descendants(multiplicity = :all, *args)
0
- with_nested_set_scope do
0
- with_find_scope(:conditions => "#{left_column_name} >= #{left}
0
- AND #{right_column_name} <= #{right}"
0
- ) { self.class.base_class.find(multiplicity, *args) }
0
- end
0
+ def self_and_descendants
0
+ Scope.new(nested_set_scope,
0
+ :conditions => "#{left_column_name} >= #{left} AND #{right_column_name} <= #{right}")
0
         end
0
 
0
         # Returns a set of all of its children and nested children
0
- def descendants(*args)
0
- without_self { self_and_descendants(*args) }
0
+ def descendants
0
+ without_self self_and_descendants
0
         end
0
 
0
         # Returns a set of only this entry's immediate children
0
- def children(multiplicity = :all, *args)
0
- with_nested_set_scope do
0
- with_find_scope(:conditions => {parent_column_name => self}) do
0
- self.class.base_class.find(multiplicity, *args)
0
- end
0
- end
0
+ def children
0
+ Scope.new(nested_set_scope, :conditions => {parent_column_name => self})
0
         end
0
 
0
         def is_descendant_of?(other)
0
- other.left < self.left && self.left < other.right && is_same_scope?(other)
0
+ other.left < self.left && self.left < other.right && same_scope?(other)
0
         end
0
         
0
         def is_or_is_descendant_of?(other)
0
- other.left <= self.left && self.left < other.right && is_same_scope?(other)
0
+ other.left <= self.left && self.left < other.right && same_scope?(other)
0
         end
0
 
0
         def is_ancestor_of?(other)
0
- self.left < other.left && other.left < self.right && is_same_scope?(other)
0
+ self.left < other.left && other.left < self.right && same_scope?(other)
0
         end
0
         
0
         def is_or_is_ancestor_of?(other)
0
- self.left <= other.left && other.left < self.right && is_same_scope?(other)
0
+ self.left <= other.left && other.left < self.right && same_scope?(other)
0
         end
0
         
0
- def is_same_scope?(other)
0
- !acts_as_nested_set_options[:scope] || self.send(scope_column_name) == other.send(scope_column_name)
0
+ # Check if other model is in the same scope
0
+ def same_scope?(other)
0
+ !acts_as_nested_set_options[:scope] ||
0
+ self.send(scope_column_name) == other.send(scope_column_name)
0
         end
0
 
0
         # Find the first sibling to the right
0
         def left_sibling
0
- if parent_id.nil?
0
- nil
0
- else
0
- with_nested_set_scope do
0
- self.class.base_class.find(:first,
0
- :conditions => ["#{quoted_left_column_name} < ? " +
0
- "AND #{quoted_parent_column_name} = ?", left, parent_id],
0
- :order => "#{left_column_name} DESC")
0
- end
0
- end
0
+ nested_set_scope.find(:first,
0
+ :conditions => ["#{quoted_left_column_name} < ? AND #{quoted_parent_column_name} = ?",
0
+ left, parent_id],
0
+ :order => "#{left_column_name} DESC"
0
+ )
0
         end
0
 
0
         # Find the first sibling to the right
0
         def right_sibling
0
- if parent_id.nil?
0
- nil
0
- else
0
- with_nested_set_scope do
0
- self.class.base_class.find(:first,
0
- :conditions => ["#{quoted_left_column_name} > ? " +
0
- "AND #{quoted_parent_column_name} = ?", left, parent_id],
0
- :order => left_column_name
0
- )
0
- end
0
- end
0
+ nested_set_scope.find(:first,
0
+ :conditions => ["#{quoted_left_column_name} > ? AND #{quoted_parent_column_name} = ?",
0
+ left, parent_id],
0
+ :order => left_column_name
0
+ )
0
         end
0
 
0
         # Shorthand method for finding the left sibling and moving to the left of it.
0
         def move_left
0
- move_to_left_of(left_sibling)
0
+ move_to_left_of left_sibling
0
         end
0
 
0
         # Shorthand method for finding the right sibling and moving to the right of it.
0
         def move_right
0
- move_to_right_of(right_sibling)
0
+ move_to_right_of right_sibling
0
         end
0
 
0
         # Move the node to the left of another node (you can pass id only)
0
@@ -482,7 +422,7 @@ module CollectiveIdea
0
           # Can't target self
0
           self != target &&
0
           # can't be in different scopes
0
- (!acts_as_nested_set_options[:scope] || self.send(scope_column_name) == target.send(scope_column_name)) &&
0
+ same_scope?(target) &&
0
           # detect impossible move
0
           # !(left..right).include?(target.left..target.right) # this needs tested more
0
           !((left <= target.left && right >= target.left) or (left <= target.right && right >= target.right))
0
@@ -496,27 +436,24 @@ module CollectiveIdea
0
         
0
       protected
0
       
0
- def without_self
0
- with_find_scope(:conditions => ["#{self.class.primary_key} != ?", self]) do
0
- yield
0
- end
0
+ def without_self(scope)
0
+ Scope.new(scope, :conditions => ["#{self.class.primary_key} != ?", self])
0
         end
0
         
0
- def with_find_scope(scope)
0
- self.class.base_class.send(:with_scope, :find => scope) { yield }
0
- end
0
-
0
- def with_nested_set_scope
0
- scope = {:order => left_column_name}
0
+ # All nested set queries should use this nested_set_scope, which performs finds on
0
+ # the base ActiveRecord class, using the :scope declared in the acts_as_nested_set
0
+ # declaration.
0
+ def nested_set_scope
0
+ options = {:order => left_column_name}
0
           if scope_column = acts_as_nested_set_options[:scope]
0
- scope[:conditions] = {scope_column => self[scope_column]}
0
+ options[:conditions] = {scope_column => self[scope_column]}
0
           end
0
- self.class.base_class.send(:with_scope, :find => scope) { yield }
0
+ Scope.new(self.class.base_class, options)
0
         end
0
-
0
+
0
         # on creation, set automatically lft and rgt to the end of the tree
0
         def set_default_left_and_right
0
- maxright = with_nested_set_scope { self.class.base_class.maximum(right_column_name) } || 0
0
+ maxright = nested_set_scope.maximum(right_column_name) || 0
0
           # adds the new node to the right of all existing nodes
0
           self[left_column_name] = maxright + 1
0
           self[right_column_name] = maxright + 2
0
@@ -528,14 +465,12 @@ module CollectiveIdea
0
           return if right.nil? || left.nil?
0
           diff = right - left + 1
0
 
0
- with_nested_set_scope do
0
- self.class.base_class.transaction do
0
- self.class.base_class.delete_all("#{left_column_name} > #{left} AND #{right_column_name} < #{right}")
0
- self.class.base_class.update_all("#{left_column_name} = (#{left_column_name} - #{diff})",
0
- "#{left_column_name} >= #{right}")
0
- self.class.base_class.update_all("#{right_column_name} = (#{right_column_name} - #{diff} )",
0
- "#{right_column_name} >= #{right}" )
0
- end
0
+ self.class.base_class.transaction do
0
+ nested_set_scope.delete_all("#{left_column_name} > #{left} AND #{right_column_name} < #{right}")
0
+ nested_set_scope.update_all("#{left_column_name} = (#{left_column_name} - #{diff})",
0
+ "#{left_column_name} >= #{right}")
0
+ nested_set_scope.update_all("#{right_column_name} = (#{right_column_name} - #{diff} )",
0
+ "#{right_column_name} >= #{right}" )
0
           end
0
         end
0
         
...
126
127
128
129
130
131
132
133
134
135
136
 
 
 
137
138
139
...
207
208
209
210
 
211
212
213
 
214
215
 
216
217
218
...
126
127
128
 
 
 
 
129
 
 
 
130
131
132
133
134
135
...
203
204
205
 
206
207
208
 
209
210
 
211
212
213
214
0
@@ -126,14 +126,10 @@ class AwesomeNestedSetTest < Test::Unit::TestCase</