nested_set 1.5.4 → 1.6.0
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile.lock +11 -1
- data/README.md +113 -0
- data/Rakefile +1 -0
- data/VERSION +1 -1
- data/lib/nested_set/base.rb +47 -13
- data/lib/nested_set/helper.rb +42 -22
- data/nested_set.gemspec +60 -33
- data/test/benchmarks.rb +55 -0
- data/test/db/schema.rb +1 -0
- data/test/fixtures/category.rb +2 -1
- data/test/nested_set/helper_test.rb +91 -65
- data/test/nested_set_test.rb +62 -1
- data/test/test_helper.rb +4 -0
- metadata +159 -29
- data/.gitignore +0 -26
- data/README.rdoc +0 -99
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
nested_set (1.5.
|
4
|
+
nested_set (1.5.4)
|
5
5
|
activerecord (>= 3.0.0)
|
6
6
|
railties (>= 3.0.0)
|
7
7
|
|
@@ -31,11 +31,20 @@ GEM
|
|
31
31
|
activesupport (3.0.0)
|
32
32
|
arel (1.0.1)
|
33
33
|
activesupport (~> 3.0.0)
|
34
|
+
bench_press (0.3.1)
|
35
|
+
activesupport (>= 2.3.5)
|
36
|
+
facter (>= 1.5.7)
|
37
|
+
httparty (>= 0.6.1)
|
38
|
+
jeweler (>= 1.4.0)
|
34
39
|
builder (2.1.2)
|
40
|
+
crack (0.1.8)
|
35
41
|
erubis (2.6.6)
|
36
42
|
abstract (>= 1.0.0)
|
43
|
+
facter (1.5.8)
|
37
44
|
gemcutter (0.6.1)
|
38
45
|
git (1.2.5)
|
46
|
+
httparty (0.6.1)
|
47
|
+
crack (= 0.1.8)
|
39
48
|
i18n (0.4.1)
|
40
49
|
jeweler (1.4.0)
|
41
50
|
gemcutter (>= 0.1.0)
|
@@ -66,6 +75,7 @@ DEPENDENCIES
|
|
66
75
|
actionpack (>= 3.0.0)
|
67
76
|
activerecord (>= 3.0.0)
|
68
77
|
activesupport (>= 3.0.0)
|
78
|
+
bench_press (>= 0.3.1)
|
69
79
|
jeweler
|
70
80
|
nested_set!
|
71
81
|
railties (>= 3.0.0)
|
data/README.md
ADDED
@@ -0,0 +1,113 @@
|
|
1
|
+
# NestedSet
|
2
|
+
|
3
|
+
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. It supports Rails 3.0 and later.
|
4
|
+
|
5
|
+
## See, it's Rails 3 only.
|
6
|
+
|
7
|
+
## Installation
|
8
|
+
|
9
|
+
The plugin is available as a gem:
|
10
|
+
|
11
|
+
gem 'nested_set'
|
12
|
+
|
13
|
+
Or install as a plugin:
|
14
|
+
|
15
|
+
rails plugin install git://github.com/skyeagle/nested_set.git
|
16
|
+
|
17
|
+
## Usage
|
18
|
+
|
19
|
+
To make use of nested_set, your model needs to have 3 fields: lft, rgt, and parent_id:
|
20
|
+
|
21
|
+
class CreateCategories < ActiveRecord::Migration
|
22
|
+
def self.up
|
23
|
+
create_table :categories do |t|
|
24
|
+
t.string :name
|
25
|
+
t.integer :parent_id
|
26
|
+
t.integer :lft
|
27
|
+
t.integer :rgt
|
28
|
+
|
29
|
+
# Uncomment it to store item level
|
30
|
+
# t.integer :depth
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def self.down
|
35
|
+
drop_table :categories
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
Enable the nested set functionality by declaring acts_as_nested_set on your model
|
40
|
+
|
41
|
+
class Category < ActiveRecord::Base
|
42
|
+
acts_as_nested_set
|
43
|
+
end
|
44
|
+
|
45
|
+
Run `rake rdoc` to generate the API docs and see CollectiveIdea::Acts::NestedSet::Base::SingletonMethods for more info.
|
46
|
+
|
47
|
+
### Conversion from other trees
|
48
|
+
|
49
|
+
Coming from acts_as_tree or another system where you only have a parent_id? No problem. Simply add the lft & rgt fields as above, and then run
|
50
|
+
|
51
|
+
Category.rebuild!
|
52
|
+
|
53
|
+
Your tree be converted to a valid nested set.
|
54
|
+
|
55
|
+
## View Helper
|
56
|
+
|
57
|
+
The view helper is called #nested_set_options.
|
58
|
+
|
59
|
+
Example usage:
|
60
|
+
|
61
|
+
<%= f.select :parent_id, nested_set_options(Category, @category) {|i, level| "#{'-' * level} #{i.name}" } %>
|
62
|
+
|
63
|
+
<%= select_tag 'parent_id', options_for_select(nested_set_options(Category) {|i, level| "#{'-' * level} #{i.name}" } ) %>
|
64
|
+
|
65
|
+
or sorted select:
|
66
|
+
|
67
|
+
<%= f.select :parent_id, sorted_nested_set_options(Category, lambda(&:name)) {|i, level| "#{'-' * level} #{i.name}" } %>
|
68
|
+
|
69
|
+
<% sort_method = lambda{|x, y| x.name.downcase <=> y.name.downcase} %>
|
70
|
+
|
71
|
+
NOTE: to sort UTF-8 strings you should use `x.name.mb_chars.downcase`
|
72
|
+
|
73
|
+
<%= select_tag 'parent_id', options_for_select(sorted_nested_set_options(Category, sort_method){|i, level| "#{'-' * level} #{i.name}" } ) %>
|
74
|
+
|
75
|
+
See CollectiveIdea::Acts::NestedSet::Helper for more information about the helpers.
|
76
|
+
|
77
|
+
## Development
|
78
|
+
|
79
|
+
bundle install
|
80
|
+
|
81
|
+
Running tests
|
82
|
+
|
83
|
+
bundle exec rake test
|
84
|
+
|
85
|
+
Benchmark tests
|
86
|
+
|
87
|
+
bundle exec ruby test/benchmark.rb
|
88
|
+
|
89
|
+
### References
|
90
|
+
|
91
|
+
You can learn more about nested sets at:
|
92
|
+
|
93
|
+
[1](http://www.dbmsmag.com/9603d06.html)
|
94
|
+
[2](http://threebit.net/tutorials/nestedset/tutorial1.html)
|
95
|
+
[3](http://api.rubyonrails.com/classes/ActiveRecord/Acts/NestedSet/ClassMethods.html)
|
96
|
+
[4](http://opensource.symetrie.com/trac/better_nested_set/)
|
97
|
+
|
98
|
+
## How to contribute
|
99
|
+
|
100
|
+
If you find what you might think is a bug:
|
101
|
+
|
102
|
+
1. Check the GitHub issue tracker to see if anyone else has had the same issue.
|
103
|
+
[Issues tracker](http://github.com/skyeagle/nested_set/issues)
|
104
|
+
2. If you don't see anything, create an issue with information on how to reproduce it.
|
105
|
+
|
106
|
+
If you want to contribute an enhancement or a fix:
|
107
|
+
|
108
|
+
1. Fork the project on github. [http://github.com/skyeagle/nested_set](http://github.com/skyeagle/nested_set)
|
109
|
+
2. Make your changes with tests.
|
110
|
+
3. Commit the changes without making changes to the Rakefile, VERSION, or any other files that aren't related to your enhancement or fix
|
111
|
+
4. Send a pull request.
|
112
|
+
|
113
|
+
Copyright ©2010 Collective Idea, released under the MIT license
|
data/Rakefile
CHANGED
@@ -16,6 +16,7 @@ begin
|
|
16
16
|
gem.add_development_dependency "sqlite3-ruby"
|
17
17
|
gem.add_development_dependency "actionpack", ['>= 3.0.0']
|
18
18
|
gem.add_development_dependency "activesupport", ['>= 3.0.0']
|
19
|
+
gem.add_development_dependency "bench_press", ['>= 0.3.1']
|
19
20
|
gem.add_development_dependency "jeweler"
|
20
21
|
end
|
21
22
|
Jeweler::GemcutterTasks.new
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
1.
|
1
|
+
1.6.0
|
data/lib/nested_set/base.rb
CHANGED
@@ -99,7 +99,7 @@ module CollectiveIdea #:nodoc:
|
|
99
99
|
where("#{quoted_right_column_name} - #{quoted_left_column_name} = 1").
|
100
100
|
order(quoted_left_column_name)
|
101
101
|
}
|
102
|
-
scope :with_depth, proc {|level| where(:depth => level).order(
|
102
|
+
scope :with_depth, proc {|level| where(:depth => level).order(quoted_left_column_name) }
|
103
103
|
|
104
104
|
define_callbacks :move, :terminator => "result == false"
|
105
105
|
end
|
@@ -113,6 +113,42 @@ module CollectiveIdea #:nodoc:
|
|
113
113
|
roots.first
|
114
114
|
end
|
115
115
|
|
116
|
+
# Returns arranged nodes hash.
|
117
|
+
# I.e. you have this tree:
|
118
|
+
#
|
119
|
+
# 1
|
120
|
+
# 2
|
121
|
+
# 3
|
122
|
+
# 4
|
123
|
+
# 5
|
124
|
+
# 6
|
125
|
+
# 7
|
126
|
+
#
|
127
|
+
# Hash will looks like:
|
128
|
+
#
|
129
|
+
# {1 => {2 => {}, 3 => {4 => {5 => {}}, 6 => {}}}, 7 => {}}
|
130
|
+
#
|
131
|
+
# == Usage:
|
132
|
+
#
|
133
|
+
# Categories.arrange
|
134
|
+
# Categories.find(42).children.arrange
|
135
|
+
# Categories.find(42).descendants.arrange
|
136
|
+
# Categories.find(42).self_and_descendants.arrange
|
137
|
+
#
|
138
|
+
# This arranged hash can be rendered with recursive render_tree helper
|
139
|
+
def arrange
|
140
|
+
arranged = ActiveSupport::OrderedHash.new
|
141
|
+
insertion_points = [arranged]
|
142
|
+
depth = 0
|
143
|
+
order(quoted_left_column_name).each_with_level do |node, level|
|
144
|
+
insertion_points.push insertion_points.last.values.last if level > depth
|
145
|
+
(depth - level).times { insertion_points.pop } if level < depth
|
146
|
+
insertion_points.last.merge! node => ActiveSupport::OrderedHash.new
|
147
|
+
depth = level
|
148
|
+
end
|
149
|
+
arranged
|
150
|
+
end
|
151
|
+
|
116
152
|
def valid?
|
117
153
|
left_and_rights_valid? && no_duplicates_for_columns? && all_roots_valid?
|
118
154
|
end
|
@@ -210,19 +246,17 @@ module CollectiveIdea #:nodoc:
|
|
210
246
|
# Example:
|
211
247
|
# Category.each_with_level(Category.root.self_and_descendants) do |o, level|
|
212
248
|
#
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
path << o.parent_id
|
223
|
-
end
|
249
|
+
|
250
|
+
def each_with_level(objects = nil)
|
251
|
+
levels = []
|
252
|
+
(objects || scoped).each do |i|
|
253
|
+
if level = levels.index(i.parent_id)
|
254
|
+
levels.slice!((level + 1)..-1)
|
255
|
+
else
|
256
|
+
levels << i.parent_id
|
257
|
+
level = levels.size - 1
|
224
258
|
end
|
225
|
-
yield(
|
259
|
+
yield(i, level)
|
226
260
|
end
|
227
261
|
end
|
228
262
|
|
data/lib/nested_set/helper.rb
CHANGED
@@ -25,19 +25,13 @@ module CollectiveIdea #:nodoc:
|
|
25
25
|
class_or_item = class_or_item.roots if class_or_item.is_a?(Class)
|
26
26
|
items = Array(class_or_item)
|
27
27
|
result = []
|
28
|
-
items.each do |
|
28
|
+
items.each do |item|
|
29
29
|
levels = []
|
30
|
-
|
31
|
-
if level = levels.index(i.parent_id)
|
32
|
-
levels.slice!((level + 1)..-1)
|
33
|
-
else
|
34
|
-
levels << i.parent_id
|
35
|
-
level = levels.size - 1
|
36
|
-
end
|
30
|
+
item.self_and_descendants.each_with_level do |i, level|
|
37
31
|
if mover.nil? || mover.new_record? || mover.move_possible?(i)
|
38
|
-
[yield(i, level), i.id]
|
32
|
+
result.push([yield(i, level), i.id])
|
39
33
|
end
|
40
|
-
end
|
34
|
+
end
|
41
35
|
end
|
42
36
|
result
|
43
37
|
end
|
@@ -61,7 +55,7 @@ module CollectiveIdea #:nodoc:
|
|
61
55
|
#
|
62
56
|
# OR
|
63
57
|
#
|
64
|
-
# sort_method = lambda{|x,y| x.name.downcase <=> y.name.downcase}
|
58
|
+
# sort_method = lambda{|x,y| x.name.mb_chars.downcase <=> y.name.mb_chars.downcase}
|
65
59
|
#
|
66
60
|
# <%= f.select :parent_id, nested_set_options(Category, sort_method) {|i, level|
|
67
61
|
# "#{'–' * level} #{i.name}"
|
@@ -71,25 +65,51 @@ module CollectiveIdea #:nodoc:
|
|
71
65
|
class_or_item = class_or_item.roots if class_or_item.is_a?(Class)
|
72
66
|
items = Array(class_or_item)
|
73
67
|
result = []
|
74
|
-
items.sort_by(&sort_proc).each do |
|
75
|
-
|
76
|
-
result += build_node(
|
68
|
+
items.sort_by(&sort_proc).each do |item|
|
69
|
+
hash = item.self_and_descendants.arrange
|
70
|
+
result += build_node(hash, sort_proc, mover, level){|x, lvl| yield(x, lvl)}
|
77
71
|
end
|
78
72
|
result
|
79
73
|
end
|
80
74
|
|
81
|
-
def build_node(
|
75
|
+
def build_node(hash, sort_proc, mover = nil, level = nil)
|
82
76
|
result ||= []
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
result.push(*build_node(i, set, sort_proc, mover, level.to_i + 1){|x, level| yield(x, level)})
|
88
|
-
}
|
77
|
+
hash.keys.sort_by(&sort_proc).each do |node|
|
78
|
+
if mover.nil? || mover.new_record? || mover.move_possible?(node)
|
79
|
+
result << [yield(node, level.to_i), node.id]
|
80
|
+
result.push(*build_node(hash[node], sort_proc, mover, level.to_i + 1){|x, lvl| yield(x, lvl)})
|
89
81
|
end
|
90
|
-
end
|
82
|
+
end if hash.present?
|
91
83
|
result
|
92
84
|
end
|
85
|
+
|
86
|
+
# Recursively render arranged nodes hash
|
87
|
+
#
|
88
|
+
# == Params
|
89
|
+
# * +hash+ - Hash or arranged nodes, i.e. Category.arranged
|
90
|
+
# * +options+ - HTML options for root ul node.
|
91
|
+
# Given options with ex. :sort => lambda{|x| x.name}
|
92
|
+
# you allow node sorting by analogy with sorted_nested_set_options helper method
|
93
|
+
# * +&block+ - A block that will be used to display node
|
94
|
+
#
|
95
|
+
# == Usage
|
96
|
+
#
|
97
|
+
# arranged_nodes = Category.arranged
|
98
|
+
#
|
99
|
+
# <%= render_tree arranged_nodes do |node, child| %>
|
100
|
+
# <li><%= node.name %></li>
|
101
|
+
# <%= child %>
|
102
|
+
# <% end %>
|
103
|
+
#
|
104
|
+
def render_tree hash, options = {}, &block
|
105
|
+
sort_proc = options.delete :sort
|
106
|
+
content_tag :ul, options do
|
107
|
+
hash.keys.sort_by(&sort_proc).each do |node|
|
108
|
+
block.call node, render_tree(hash[node], :sort => sort_proc, &block)
|
109
|
+
end
|
110
|
+
end if hash.present?
|
111
|
+
end
|
112
|
+
|
93
113
|
end
|
94
114
|
end
|
95
115
|
end
|
data/nested_set.gemspec
CHANGED
@@ -5,55 +5,55 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{nested_set}
|
8
|
-
s.version = "1.
|
8
|
+
s.version = "1.6.0"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Brandon Keepers", "Daniel Morrison"]
|
12
|
-
s.date = %q{2010-11
|
12
|
+
s.date = %q{2010-12-11}
|
13
13
|
s.description = %q{An awesome nested set implementation for Active Record}
|
14
14
|
s.email = %q{info@collectiveidea.com}
|
15
15
|
s.extra_rdoc_files = [
|
16
|
-
"README.
|
16
|
+
"README.md"
|
17
17
|
]
|
18
18
|
s.files = [
|
19
19
|
".autotest",
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
20
|
+
"Gemfile",
|
21
|
+
"Gemfile.lock",
|
22
|
+
"MIT-LICENSE",
|
23
|
+
"README.md",
|
24
|
+
"Rakefile",
|
25
|
+
"VERSION",
|
26
|
+
"init.rb",
|
27
|
+
"lib/nested_set.rb",
|
28
|
+
"lib/nested_set/base.rb",
|
29
|
+
"lib/nested_set/depth.rb",
|
30
|
+
"lib/nested_set/descendants.rb",
|
31
|
+
"lib/nested_set/helper.rb",
|
32
|
+
"lib/nested_set/railtie.rb",
|
33
|
+
"nested_set.gemspec",
|
34
|
+
"rails/init.rb",
|
35
|
+
"test/benchmarks.rb",
|
36
|
+
"test/db/database.yml",
|
37
|
+
"test/db/schema.rb",
|
38
|
+
"test/fixtures/categories.yml",
|
39
|
+
"test/fixtures/category.rb",
|
40
|
+
"test/fixtures/departments.yml",
|
41
|
+
"test/fixtures/notes.yml",
|
42
|
+
"test/nested_set/helper_test.rb",
|
43
|
+
"test/nested_set_test.rb",
|
44
|
+
"test/test_helper.rb"
|
45
45
|
]
|
46
46
|
s.homepage = %q{http://github.com/skyeagle/nested_set}
|
47
|
-
s.rdoc_options = ["--charset=UTF-8"]
|
48
47
|
s.require_paths = ["lib"]
|
49
48
|
s.rubygems_version = %q{1.3.7}
|
50
49
|
s.summary = %q{An awesome nested set implementation for Active Record}
|
51
50
|
s.test_files = [
|
51
|
+
"test/benchmarks.rb",
|
52
|
+
"test/db/schema.rb",
|
53
|
+
"test/fixtures/category.rb",
|
54
|
+
"test/nested_set/helper_test.rb",
|
52
55
|
"test/nested_set_test.rb",
|
53
|
-
|
54
|
-
"test/test_helper.rb",
|
55
|
-
"test/fixtures/category.rb",
|
56
|
-
"test/db/schema.rb"
|
56
|
+
"test/test_helper.rb"
|
57
57
|
]
|
58
58
|
|
59
59
|
if s.respond_to? :specification_version then
|
@@ -61,26 +61,53 @@ Gem::Specification.new do |s|
|
|
61
61
|
s.specification_version = 3
|
62
62
|
|
63
63
|
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
64
|
+
s.add_runtime_dependency(%q<nested_set>, [">= 0"])
|
65
|
+
s.add_runtime_dependency(%q<railties>, [">= 3.0.0"])
|
66
|
+
s.add_runtime_dependency(%q<activerecord>, [">= 3.0.0"])
|
67
|
+
s.add_development_dependency(%q<sqlite3-ruby>, [">= 0"])
|
68
|
+
s.add_development_dependency(%q<actionpack>, [">= 3.0.0"])
|
69
|
+
s.add_development_dependency(%q<activesupport>, [">= 3.0.0"])
|
70
|
+
s.add_development_dependency(%q<bench_press>, [">= 0.3.1"])
|
71
|
+
s.add_development_dependency(%q<jeweler>, [">= 0"])
|
64
72
|
s.add_runtime_dependency(%q<railties>, [">= 3.0.0"])
|
65
73
|
s.add_runtime_dependency(%q<activerecord>, [">= 3.0.0"])
|
66
74
|
s.add_development_dependency(%q<sqlite3-ruby>, [">= 0"])
|
67
75
|
s.add_development_dependency(%q<actionpack>, [">= 3.0.0"])
|
68
76
|
s.add_development_dependency(%q<activesupport>, [">= 3.0.0"])
|
77
|
+
s.add_development_dependency(%q<bench_press>, [">= 0.3.1"])
|
69
78
|
s.add_development_dependency(%q<jeweler>, [">= 0"])
|
70
79
|
else
|
80
|
+
s.add_dependency(%q<nested_set>, [">= 0"])
|
71
81
|
s.add_dependency(%q<railties>, [">= 3.0.0"])
|
72
82
|
s.add_dependency(%q<activerecord>, [">= 3.0.0"])
|
73
83
|
s.add_dependency(%q<sqlite3-ruby>, [">= 0"])
|
74
84
|
s.add_dependency(%q<actionpack>, [">= 3.0.0"])
|
75
85
|
s.add_dependency(%q<activesupport>, [">= 3.0.0"])
|
86
|
+
s.add_dependency(%q<bench_press>, [">= 0.3.1"])
|
87
|
+
s.add_dependency(%q<jeweler>, [">= 0"])
|
88
|
+
s.add_dependency(%q<railties>, [">= 3.0.0"])
|
89
|
+
s.add_dependency(%q<activerecord>, [">= 3.0.0"])
|
90
|
+
s.add_dependency(%q<sqlite3-ruby>, [">= 0"])
|
91
|
+
s.add_dependency(%q<actionpack>, [">= 3.0.0"])
|
92
|
+
s.add_dependency(%q<activesupport>, [">= 3.0.0"])
|
93
|
+
s.add_dependency(%q<bench_press>, [">= 0.3.1"])
|
76
94
|
s.add_dependency(%q<jeweler>, [">= 0"])
|
77
95
|
end
|
78
96
|
else
|
97
|
+
s.add_dependency(%q<nested_set>, [">= 0"])
|
98
|
+
s.add_dependency(%q<railties>, [">= 3.0.0"])
|
99
|
+
s.add_dependency(%q<activerecord>, [">= 3.0.0"])
|
100
|
+
s.add_dependency(%q<sqlite3-ruby>, [">= 0"])
|
101
|
+
s.add_dependency(%q<actionpack>, [">= 3.0.0"])
|
102
|
+
s.add_dependency(%q<activesupport>, [">= 3.0.0"])
|
103
|
+
s.add_dependency(%q<bench_press>, [">= 0.3.1"])
|
104
|
+
s.add_dependency(%q<jeweler>, [">= 0"])
|
79
105
|
s.add_dependency(%q<railties>, [">= 3.0.0"])
|
80
106
|
s.add_dependency(%q<activerecord>, [">= 3.0.0"])
|
81
107
|
s.add_dependency(%q<sqlite3-ruby>, [">= 0"])
|
82
108
|
s.add_dependency(%q<actionpack>, [">= 3.0.0"])
|
83
109
|
s.add_dependency(%q<activesupport>, [">= 3.0.0"])
|
110
|
+
s.add_dependency(%q<bench_press>, [">= 0.3.1"])
|
84
111
|
s.add_dependency(%q<jeweler>, [">= 0"])
|
85
112
|
end
|
86
113
|
end
|
data/test/benchmarks.rb
ADDED
@@ -0,0 +1,55 @@
|
|
1
|
+
if $0 == __FILE__
|
2
|
+
|
3
|
+
plugin_test_dir = File.dirname(__FILE__)
|
4
|
+
|
5
|
+
$:.unshift(plugin_test_dir + '/../lib')
|
6
|
+
|
7
|
+
#require 'logger'
|
8
|
+
require 'active_support'
|
9
|
+
require 'active_record'
|
10
|
+
require 'nested_set'
|
11
|
+
require 'bench_press'
|
12
|
+
|
13
|
+
|
14
|
+
CollectiveIdea::Acts::NestedSet::Railtie.extend_active_record
|
15
|
+
#ActiveRecord::Base.logger = Logger.new(plugin_test_dir + "/debug.log")
|
16
|
+
ActiveRecord::Base.configurations = YAML::load(IO.read(plugin_test_dir + "/db/database.yml"))
|
17
|
+
ActiveRecord::Base.establish_connection(ENV["DB"] || "sqlite3mem")
|
18
|
+
ActiveRecord::Migration.verbose = false
|
19
|
+
ActiveRecord::Schema.define(:version => 0) do
|
20
|
+
create_table :categories, :force => true do |t|
|
21
|
+
t.column :name, :string
|
22
|
+
t.column :parent_id, :integer
|
23
|
+
t.column :lft, :integer
|
24
|
+
t.column :rgt, :integer
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
class Category < ActiveRecord::Base
|
29
|
+
acts_as_nested_set
|
30
|
+
end
|
31
|
+
|
32
|
+
Category.delete_all
|
33
|
+
Category.create(:name => "Root Node 1")
|
34
|
+
Category.create(:name => "Root Node 2")
|
35
|
+
50.times do |i|
|
36
|
+
node = Category.create(:name => "Node #{i}")
|
37
|
+
set = Category.roots.map{|root| root.self_and_descendants}.flatten
|
38
|
+
random_node = set[rand(set.size-1)]
|
39
|
+
node.move_to_child_of(random_node)
|
40
|
+
end
|
41
|
+
|
42
|
+
include CollectiveIdea::Acts::NestedSet::Helper
|
43
|
+
extend BenchPress
|
44
|
+
|
45
|
+
reps 100
|
46
|
+
|
47
|
+
measure "nested_set_options" do
|
48
|
+
nested_set_options(Category){|i, level| "#{'-' * level} #{i.name}" }
|
49
|
+
end
|
50
|
+
|
51
|
+
measure "sorted_nested_set_options" do
|
52
|
+
sorted_nested_set_options(Category, lambda(&:name)){|i, level| "#{'-' * level} #{i.name}" }
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
data/test/db/schema.rb
CHANGED
data/test/fixtures/category.rb
CHANGED
@@ -1,77 +1,103 @@
|
|
1
1
|
require 'test_helper'
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
class NestedSetTest < ActiveSupport::TestCase
|
7
|
-
include Helper
|
8
|
-
fixtures :categories
|
3
|
+
class HelperTest < ActionView::TestCase
|
4
|
+
include CollectiveIdea::Acts::NestedSet::Helper
|
5
|
+
fixtures :categories
|
9
6
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
7
|
+
def test_nested_set_options
|
8
|
+
expected = [
|
9
|
+
[" Top Level", 1],
|
10
|
+
["- Child 1", 2],
|
11
|
+
['- Child 2', 3],
|
12
|
+
['-- Child 2.1', 4],
|
13
|
+
['- Child 3', 5],
|
14
|
+
[" Top Level 2", 6]
|
15
|
+
]
|
16
|
+
actual = nested_set_options(Category) do |c, level|
|
17
|
+
"#{'-' * level} #{c.name}"
|
18
|
+
end
|
19
|
+
assert_equal expected, actual
|
20
|
+
end
|
24
21
|
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
22
|
+
def test_nested_set_options_with_mover
|
23
|
+
expected = [
|
24
|
+
[" Top Level", 1],
|
25
|
+
["- Child 1", 2],
|
26
|
+
['- Child 3', 5],
|
27
|
+
[" Top Level 2", 6]
|
28
|
+
]
|
29
|
+
actual = nested_set_options(Category, categories(:child_2)) do |c, level|
|
30
|
+
"#{'-' * level} #{c.name}"
|
31
|
+
end
|
32
|
+
assert_equal expected, actual
|
33
|
+
end
|
37
34
|
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
actual = build_node(set[0], set, lambda(&:lft)){|i, level| i.name }
|
42
|
-
assert_equal expected, actual
|
43
|
-
end
|
35
|
+
def test_build_node
|
36
|
+
set = categories(:top_level).self_and_descendants
|
37
|
+
expected = set.map{|i| [i.name, i.id]}
|
44
38
|
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
["Child 3", 5],
|
50
|
-
["Child 2", 3],
|
51
|
-
["Child 2.1", 4],
|
52
|
-
["Child 1", 2]
|
53
|
-
]
|
54
|
-
actual = build_node(set[0], set, lambda{|x| -x.id}){|i, level| i.name }
|
55
|
-
assert_equal expected, actual
|
56
|
-
end
|
39
|
+
hash = set.arrange
|
40
|
+
actual = build_node(hash, lambda(&:lft)){|i, level| i.name }
|
41
|
+
assert_equal expected, actual
|
42
|
+
end
|
57
43
|
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
]
|
44
|
+
def test_build_node_with_back_id_order
|
45
|
+
expected = [
|
46
|
+
["Top Level", 1],
|
47
|
+
["Child 3", 5],
|
48
|
+
["Child 2", 3],
|
49
|
+
["Child 2.1", 4],
|
50
|
+
["Child 1", 2]
|
51
|
+
]
|
67
52
|
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
53
|
+
hash = categories(:top_level).self_and_descendants.arrange
|
54
|
+
actual = build_node(hash, lambda{|x| -x.id}){|i, level| i.name }
|
55
|
+
assert_equal expected, actual
|
56
|
+
end
|
57
|
+
|
58
|
+
def test_sorted_nested_set
|
59
|
+
expected = [
|
60
|
+
[" Top Level 2", 6],
|
61
|
+
[" Top Level", 1],
|
62
|
+
['- Child 3', 5],
|
63
|
+
['- Child 2', 3],
|
64
|
+
['-- Child 2.1', 4],
|
65
|
+
["- Child 1", 2]
|
66
|
+
]
|
73
67
|
|
74
|
-
|
68
|
+
actual = sorted_nested_set_options(Category, lambda{|x| -x.id}) do |c, level|
|
69
|
+
"#{'-' * level} #{c.name}"
|
75
70
|
end
|
71
|
+
assert_equal expected, actual
|
76
72
|
end
|
73
|
+
|
74
|
+
def test_sorted_nested_set_with_mover
|
75
|
+
expected = [
|
76
|
+
[" Top Level 2", 6],
|
77
|
+
[" Top Level", 1],
|
78
|
+
['- Child 3', 5],
|
79
|
+
["- Child 1", 2]
|
80
|
+
]
|
81
|
+
|
82
|
+
actual = sorted_nested_set_options(Category, lambda{|x| -x.id}, categories(:child_2)) do |c, level|
|
83
|
+
"#{'-' * level} #{c.name}"
|
84
|
+
end
|
85
|
+
assert_equal expected, actual
|
86
|
+
end
|
87
|
+
def test_render_tree
|
88
|
+
html = render_tree(Category.arrange) do |category, child|
|
89
|
+
concat content_tag(:li, category)
|
90
|
+
concat child
|
91
|
+
end
|
92
|
+
assert_equal html, "<ul><li>Top Level</li><ul><li>Child 1</li><li>Child 2</li><ul><li>Child 2.1</li></ul><li>Child 3</li></ul><li>Top Level 2</li></ul>"
|
93
|
+
end
|
94
|
+
|
95
|
+
def test_sorted_render_tree
|
96
|
+
html = render_tree(Category.arrange, :sort => lambda{|x| -x.id}) do |category, child|
|
97
|
+
concat content_tag(:li, category)
|
98
|
+
concat child
|
99
|
+
end
|
100
|
+
assert_equal html, "<ul><li>Top Level 2</li><li>Top Level</li><ul><li>Child 3</li><li>Child 2</li><ul><li>Child 2.1</li></ul><li>Child 1</li></ul></ul>"
|
101
|
+
end
|
102
|
+
|
77
103
|
end
|
data/test/nested_set_test.rb
CHANGED
@@ -712,6 +712,15 @@ class NestedSetTest < ActiveSupport::TestCase
|
|
712
712
|
end
|
713
713
|
end
|
714
714
|
|
715
|
+
def check_scoped_structure(entries, structure)
|
716
|
+
structure = structure.dup
|
717
|
+
entries.each_with_level do |category, level|
|
718
|
+
expected_level, expected_name = structure.shift
|
719
|
+
assert_equal expected_name, category.name, "wrong category"
|
720
|
+
assert_equal expected_level, level, "wrong level for #{category.name}"
|
721
|
+
end
|
722
|
+
end
|
723
|
+
|
715
724
|
def test_each_with_level
|
716
725
|
levels = [
|
717
726
|
[0, "Top Level"],
|
@@ -721,6 +730,7 @@ class NestedSetTest < ActiveSupport::TestCase
|
|
721
730
|
[1, "Child 3" ]]
|
722
731
|
|
723
732
|
check_structure(Category.root.self_and_descendants, levels)
|
733
|
+
check_scoped_structure(Category.root.self_and_descendants, levels)
|
724
734
|
|
725
735
|
# test some deeper structures
|
726
736
|
category = Category.find_by_name("Child 1")
|
@@ -746,7 +756,7 @@ class NestedSetTest < ActiveSupport::TestCase
|
|
746
756
|
[2, "Child 2.1"],
|
747
757
|
[1, "Child 3" ]]
|
748
758
|
|
749
|
-
|
759
|
+
check_scoped_structure(Category.root.self_and_descendants, levels)
|
750
760
|
end
|
751
761
|
|
752
762
|
def test_model_with_attr_accessible
|
@@ -801,4 +811,55 @@ class NestedSetTest < ActiveSupport::TestCase
|
|
801
811
|
ensure
|
802
812
|
Category.class_eval { reset_callbacks :move }
|
803
813
|
end
|
814
|
+
|
815
|
+
# helper to turn arranged hash to levels array
|
816
|
+
def hash_to_array hash, level = 0
|
817
|
+
array = []
|
818
|
+
hash.each do |key, value|
|
819
|
+
array.push [level, "#{key}"]
|
820
|
+
array += hash_to_array(value, level.next)
|
821
|
+
end
|
822
|
+
array
|
823
|
+
end
|
824
|
+
|
825
|
+
def test_arrangement
|
826
|
+
levels = [
|
827
|
+
[0, "Top Level"],
|
828
|
+
[1, "Child 1"],
|
829
|
+
[1, "Child 2"],
|
830
|
+
[2, "Child 2.1"],
|
831
|
+
[1, "Child 3"],
|
832
|
+
[0, "Top Level 2"]]
|
833
|
+
|
834
|
+
assert_equal hash_to_array(Category.arrange), levels
|
835
|
+
|
836
|
+
# some deeper structure
|
837
|
+
|
838
|
+
category = Category.find_by_name("Child 1")
|
839
|
+
c1 = Category.new(:name => "Child 1.1")
|
840
|
+
c2 = Category.new(:name => "Child 1.1.1")
|
841
|
+
c3 = Category.new(:name => "Child 1.1.1.1")
|
842
|
+
c4 = Category.new(:name => "Child 1.2")
|
843
|
+
[c1, c2, c3, c4].each(&:save!)
|
844
|
+
|
845
|
+
c1.move_to_child_of(category)
|
846
|
+
c2.move_to_child_of(c1)
|
847
|
+
c3.move_to_child_of(c2)
|
848
|
+
c4.move_to_child_of(category)
|
849
|
+
|
850
|
+
levels = [
|
851
|
+
[0, "Top Level"],
|
852
|
+
[1, "Child 1"],
|
853
|
+
[2, "Child 1.1"],
|
854
|
+
[3, "Child 1.1.1"],
|
855
|
+
[4, "Child 1.1.1.1"],
|
856
|
+
[2, "Child 1.2"],
|
857
|
+
[1, "Child 2"],
|
858
|
+
[2, "Child 2.1"],
|
859
|
+
[1, "Child 3" ],
|
860
|
+
[0, "Top Level 2"]]
|
861
|
+
|
862
|
+
assert_equal hash_to_array(Category.arrange), levels
|
863
|
+
end
|
864
|
+
|
804
865
|
end
|
data/test/test_helper.rb
CHANGED
@@ -9,6 +9,10 @@ require 'active_support'
|
|
9
9
|
require 'active_support/test_case'
|
10
10
|
require 'active_record'
|
11
11
|
require 'action_pack'
|
12
|
+
require 'action_view'
|
13
|
+
require 'action_view/base'
|
14
|
+
require 'action_view/template/handlers/erb'
|
15
|
+
require 'action_view/test_case'
|
12
16
|
require 'nested_set'
|
13
17
|
|
14
18
|
CollectiveIdea::Acts::NestedSet::Railtie.extend_active_record
|
metadata
CHANGED
@@ -4,9 +4,9 @@ version: !ruby/object:Gem::Version
|
|
4
4
|
prerelease: false
|
5
5
|
segments:
|
6
6
|
- 1
|
7
|
-
-
|
8
|
-
-
|
9
|
-
version: 1.
|
7
|
+
- 6
|
8
|
+
- 0
|
9
|
+
version: 1.6.0
|
10
10
|
platform: ruby
|
11
11
|
authors:
|
12
12
|
- Brandon Keepers
|
@@ -15,13 +15,25 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2010-11
|
18
|
+
date: 2010-12-11 00:00:00 +03:00
|
19
19
|
default_executable:
|
20
20
|
dependencies:
|
21
21
|
- !ruby/object:Gem::Dependency
|
22
|
-
name:
|
23
|
-
prerelease: false
|
22
|
+
name: nested_set
|
24
23
|
requirement: &id001 !ruby/object:Gem::Requirement
|
24
|
+
none: false
|
25
|
+
requirements:
|
26
|
+
- - ">="
|
27
|
+
- !ruby/object:Gem::Version
|
28
|
+
segments:
|
29
|
+
- 0
|
30
|
+
version: "0"
|
31
|
+
type: :runtime
|
32
|
+
prerelease: false
|
33
|
+
version_requirements: *id001
|
34
|
+
- !ruby/object:Gem::Dependency
|
35
|
+
name: railties
|
36
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
25
37
|
none: false
|
26
38
|
requirements:
|
27
39
|
- - ">="
|
@@ -32,11 +44,11 @@ dependencies:
|
|
32
44
|
- 0
|
33
45
|
version: 3.0.0
|
34
46
|
type: :runtime
|
35
|
-
|
47
|
+
prerelease: false
|
48
|
+
version_requirements: *id002
|
36
49
|
- !ruby/object:Gem::Dependency
|
37
50
|
name: activerecord
|
38
|
-
|
39
|
-
requirement: &id002 !ruby/object:Gem::Requirement
|
51
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
40
52
|
none: false
|
41
53
|
requirements:
|
42
54
|
- - ">="
|
@@ -47,11 +59,11 @@ dependencies:
|
|
47
59
|
- 0
|
48
60
|
version: 3.0.0
|
49
61
|
type: :runtime
|
50
|
-
|
62
|
+
prerelease: false
|
63
|
+
version_requirements: *id003
|
51
64
|
- !ruby/object:Gem::Dependency
|
52
65
|
name: sqlite3-ruby
|
53
|
-
|
54
|
-
requirement: &id003 !ruby/object:Gem::Requirement
|
66
|
+
requirement: &id004 !ruby/object:Gem::Requirement
|
55
67
|
none: false
|
56
68
|
requirements:
|
57
69
|
- - ">="
|
@@ -60,11 +72,11 @@ dependencies:
|
|
60
72
|
- 0
|
61
73
|
version: "0"
|
62
74
|
type: :development
|
63
|
-
|
75
|
+
prerelease: false
|
76
|
+
version_requirements: *id004
|
64
77
|
- !ruby/object:Gem::Dependency
|
65
78
|
name: actionpack
|
66
|
-
|
67
|
-
requirement: &id004 !ruby/object:Gem::Requirement
|
79
|
+
requirement: &id005 !ruby/object:Gem::Requirement
|
68
80
|
none: false
|
69
81
|
requirements:
|
70
82
|
- - ">="
|
@@ -75,11 +87,11 @@ dependencies:
|
|
75
87
|
- 0
|
76
88
|
version: 3.0.0
|
77
89
|
type: :development
|
78
|
-
|
90
|
+
prerelease: false
|
91
|
+
version_requirements: *id005
|
79
92
|
- !ruby/object:Gem::Dependency
|
80
93
|
name: activesupport
|
81
|
-
|
82
|
-
requirement: &id005 !ruby/object:Gem::Requirement
|
94
|
+
requirement: &id006 !ruby/object:Gem::Requirement
|
83
95
|
none: false
|
84
96
|
requirements:
|
85
97
|
- - ">="
|
@@ -90,11 +102,69 @@ dependencies:
|
|
90
102
|
- 0
|
91
103
|
version: 3.0.0
|
92
104
|
type: :development
|
93
|
-
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: *id006
|
107
|
+
- !ruby/object:Gem::Dependency
|
108
|
+
name: bench_press
|
109
|
+
requirement: &id007 !ruby/object:Gem::Requirement
|
110
|
+
none: false
|
111
|
+
requirements:
|
112
|
+
- - ">="
|
113
|
+
- !ruby/object:Gem::Version
|
114
|
+
segments:
|
115
|
+
- 0
|
116
|
+
- 3
|
117
|
+
- 1
|
118
|
+
version: 0.3.1
|
119
|
+
type: :development
|
120
|
+
prerelease: false
|
121
|
+
version_requirements: *id007
|
94
122
|
- !ruby/object:Gem::Dependency
|
95
123
|
name: jeweler
|
124
|
+
requirement: &id008 !ruby/object:Gem::Requirement
|
125
|
+
none: false
|
126
|
+
requirements:
|
127
|
+
- - ">="
|
128
|
+
- !ruby/object:Gem::Version
|
129
|
+
segments:
|
130
|
+
- 0
|
131
|
+
version: "0"
|
132
|
+
type: :development
|
96
133
|
prerelease: false
|
97
|
-
|
134
|
+
version_requirements: *id008
|
135
|
+
- !ruby/object:Gem::Dependency
|
136
|
+
name: railties
|
137
|
+
requirement: &id009 !ruby/object:Gem::Requirement
|
138
|
+
none: false
|
139
|
+
requirements:
|
140
|
+
- - ">="
|
141
|
+
- !ruby/object:Gem::Version
|
142
|
+
segments:
|
143
|
+
- 3
|
144
|
+
- 0
|
145
|
+
- 0
|
146
|
+
version: 3.0.0
|
147
|
+
type: :runtime
|
148
|
+
prerelease: false
|
149
|
+
version_requirements: *id009
|
150
|
+
- !ruby/object:Gem::Dependency
|
151
|
+
name: activerecord
|
152
|
+
requirement: &id010 !ruby/object:Gem::Requirement
|
153
|
+
none: false
|
154
|
+
requirements:
|
155
|
+
- - ">="
|
156
|
+
- !ruby/object:Gem::Version
|
157
|
+
segments:
|
158
|
+
- 3
|
159
|
+
- 0
|
160
|
+
- 0
|
161
|
+
version: 3.0.0
|
162
|
+
type: :runtime
|
163
|
+
prerelease: false
|
164
|
+
version_requirements: *id010
|
165
|
+
- !ruby/object:Gem::Dependency
|
166
|
+
name: sqlite3-ruby
|
167
|
+
requirement: &id011 !ruby/object:Gem::Requirement
|
98
168
|
none: false
|
99
169
|
requirements:
|
100
170
|
- - ">="
|
@@ -103,7 +173,66 @@ dependencies:
|
|
103
173
|
- 0
|
104
174
|
version: "0"
|
105
175
|
type: :development
|
106
|
-
|
176
|
+
prerelease: false
|
177
|
+
version_requirements: *id011
|
178
|
+
- !ruby/object:Gem::Dependency
|
179
|
+
name: actionpack
|
180
|
+
requirement: &id012 !ruby/object:Gem::Requirement
|
181
|
+
none: false
|
182
|
+
requirements:
|
183
|
+
- - ">="
|
184
|
+
- !ruby/object:Gem::Version
|
185
|
+
segments:
|
186
|
+
- 3
|
187
|
+
- 0
|
188
|
+
- 0
|
189
|
+
version: 3.0.0
|
190
|
+
type: :development
|
191
|
+
prerelease: false
|
192
|
+
version_requirements: *id012
|
193
|
+
- !ruby/object:Gem::Dependency
|
194
|
+
name: activesupport
|
195
|
+
requirement: &id013 !ruby/object:Gem::Requirement
|
196
|
+
none: false
|
197
|
+
requirements:
|
198
|
+
- - ">="
|
199
|
+
- !ruby/object:Gem::Version
|
200
|
+
segments:
|
201
|
+
- 3
|
202
|
+
- 0
|
203
|
+
- 0
|
204
|
+
version: 3.0.0
|
205
|
+
type: :development
|
206
|
+
prerelease: false
|
207
|
+
version_requirements: *id013
|
208
|
+
- !ruby/object:Gem::Dependency
|
209
|
+
name: bench_press
|
210
|
+
requirement: &id014 !ruby/object:Gem::Requirement
|
211
|
+
none: false
|
212
|
+
requirements:
|
213
|
+
- - ">="
|
214
|
+
- !ruby/object:Gem::Version
|
215
|
+
segments:
|
216
|
+
- 0
|
217
|
+
- 3
|
218
|
+
- 1
|
219
|
+
version: 0.3.1
|
220
|
+
type: :development
|
221
|
+
prerelease: false
|
222
|
+
version_requirements: *id014
|
223
|
+
- !ruby/object:Gem::Dependency
|
224
|
+
name: jeweler
|
225
|
+
requirement: &id015 !ruby/object:Gem::Requirement
|
226
|
+
none: false
|
227
|
+
requirements:
|
228
|
+
- - ">="
|
229
|
+
- !ruby/object:Gem::Version
|
230
|
+
segments:
|
231
|
+
- 0
|
232
|
+
version: "0"
|
233
|
+
type: :development
|
234
|
+
prerelease: false
|
235
|
+
version_requirements: *id015
|
107
236
|
description: An awesome nested set implementation for Active Record
|
108
237
|
email: info@collectiveidea.com
|
109
238
|
executables: []
|
@@ -111,14 +240,13 @@ executables: []
|
|
111
240
|
extensions: []
|
112
241
|
|
113
242
|
extra_rdoc_files:
|
114
|
-
- README.
|
243
|
+
- README.md
|
115
244
|
files:
|
116
245
|
- .autotest
|
117
|
-
- .gitignore
|
118
246
|
- Gemfile
|
119
247
|
- Gemfile.lock
|
120
248
|
- MIT-LICENSE
|
121
|
-
- README.
|
249
|
+
- README.md
|
122
250
|
- Rakefile
|
123
251
|
- VERSION
|
124
252
|
- init.rb
|
@@ -130,6 +258,7 @@ files:
|
|
130
258
|
- lib/nested_set/railtie.rb
|
131
259
|
- nested_set.gemspec
|
132
260
|
- rails/init.rb
|
261
|
+
- test/benchmarks.rb
|
133
262
|
- test/db/database.yml
|
134
263
|
- test/db/schema.rb
|
135
264
|
- test/fixtures/categories.yml
|
@@ -144,8 +273,8 @@ homepage: http://github.com/skyeagle/nested_set
|
|
144
273
|
licenses: []
|
145
274
|
|
146
275
|
post_install_message:
|
147
|
-
rdoc_options:
|
148
|
-
|
276
|
+
rdoc_options: []
|
277
|
+
|
149
278
|
require_paths:
|
150
279
|
- lib
|
151
280
|
required_ruby_version: !ruby/object:Gem::Requirement
|
@@ -172,8 +301,9 @@ signing_key:
|
|
172
301
|
specification_version: 3
|
173
302
|
summary: An awesome nested set implementation for Active Record
|
174
303
|
test_files:
|
175
|
-
- test/
|
304
|
+
- test/benchmarks.rb
|
305
|
+
- test/db/schema.rb
|
306
|
+
- test/fixtures/category.rb
|
176
307
|
- test/nested_set/helper_test.rb
|
308
|
+
- test/nested_set_test.rb
|
177
309
|
- test/test_helper.rb
|
178
|
-
- test/fixtures/category.rb
|
179
|
-
- test/db/schema.rb
|
data/.gitignore
DELETED
@@ -1,26 +0,0 @@
|
|
1
|
-
## MAC OS
|
2
|
-
.DS_Store
|
3
|
-
|
4
|
-
## TEXTMATE
|
5
|
-
*.tmproj
|
6
|
-
tmtags
|
7
|
-
|
8
|
-
## EMACS
|
9
|
-
*~
|
10
|
-
\#*
|
11
|
-
.\#*
|
12
|
-
|
13
|
-
## VIM
|
14
|
-
*.swp
|
15
|
-
|
16
|
-
## PROJECT::GENERAL
|
17
|
-
coverage
|
18
|
-
rdoc
|
19
|
-
pkg
|
20
|
-
|
21
|
-
# PROJECT::SPECIFIC
|
22
|
-
awesome_nested_set.sqlite3.db
|
23
|
-
test/debug.log
|
24
|
-
rdoc
|
25
|
-
*.sw?
|
26
|
-
.bundle
|
data/README.rdoc
DELETED
@@ -1,99 +0,0 @@
|
|
1
|
-
= NestedSet
|
2
|
-
|
3
|
-
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. It supports Rails 3.0 and later.
|
4
|
-
|
5
|
-
=== See, it's Rails 3 only.
|
6
|
-
|
7
|
-
== Installation
|
8
|
-
|
9
|
-
The plugin is available as a gem:
|
10
|
-
|
11
|
-
gem 'nested_set'
|
12
|
-
|
13
|
-
Or install as a plugin:
|
14
|
-
|
15
|
-
rails plugin install git://github.com/skyeagle/nested_set.git
|
16
|
-
|
17
|
-
== Usage
|
18
|
-
|
19
|
-
To make use of nested_set, your model needs to have 3 fields: lft, rgt, and parent_id:
|
20
|
-
|
21
|
-
class CreateCategories < ActiveRecord::Migration
|
22
|
-
def self.up
|
23
|
-
create_table :categories do |t|
|
24
|
-
t.string :name
|
25
|
-
t.integer :parent_id
|
26
|
-
t.integer :lft
|
27
|
-
t.integer :rgt
|
28
|
-
|
29
|
-
# Uncomment it to store item level
|
30
|
-
# t.integer :depth
|
31
|
-
end
|
32
|
-
end
|
33
|
-
|
34
|
-
def self.down
|
35
|
-
drop_table :categories
|
36
|
-
end
|
37
|
-
end
|
38
|
-
|
39
|
-
Enable the nested set functionality by declaring acts_as_nested_set on your model
|
40
|
-
|
41
|
-
class Category < ActiveRecord::Base
|
42
|
-
acts_as_nested_set
|
43
|
-
end
|
44
|
-
|
45
|
-
Run `rake rdoc` to generate the API docs and see CollectiveIdea::Acts::NestedSet::Base::SingletonMethods for more info.
|
46
|
-
|
47
|
-
== Conversion from other trees
|
48
|
-
|
49
|
-
Coming from acts_as_tree or another system where you only have a parent_id? No problem. Simply add the lft & rgt fields as above, and then run
|
50
|
-
|
51
|
-
Category.rebuild!
|
52
|
-
|
53
|
-
Your tree be converted to a valid nested set.
|
54
|
-
|
55
|
-
== View Helper
|
56
|
-
|
57
|
-
The view helper is called #nested_set_options.
|
58
|
-
|
59
|
-
Example usage:
|
60
|
-
|
61
|
-
<%= f.select :parent_id, nested_set_options(Category, @category) {|i| "#{'-' * i.level} #{i.name}" } %>
|
62
|
-
|
63
|
-
<%= select_tag 'parent_id', options_for_select(nested_set_options(Category) {|i| "#{'-' * i.level} #{i.name}" } ) %>
|
64
|
-
|
65
|
-
or sorted select:
|
66
|
-
|
67
|
-
<%= f.select :parent_id, sorted_nested_set_options(Category, lambda(&:name)) {|i| "#{'-' * i.level} #{i.name}" } %>
|
68
|
-
|
69
|
-
<% sort_method = lambda{|x, y| x.name.downcase <=> y.name.downcase} %>
|
70
|
-
<%= select_tag 'parent_id', options_for_select(sorted_nested_set_options(Category, sort_method){|i| "#{'-' * i.level} #{i.name}" } ) %>
|
71
|
-
|
72
|
-
See CollectiveIdea::Acts::NestedSet::Helper for more information about the helpers.
|
73
|
-
|
74
|
-
== References
|
75
|
-
|
76
|
-
You can learn more about nested sets at:
|
77
|
-
|
78
|
-
http://www.dbmsmag.com/9603d06.html
|
79
|
-
http://threebit.net/tutorials/nestedset/tutorial1.html
|
80
|
-
http://api.rubyonrails.com/classes/ActiveRecord/Acts/NestedSet/ClassMethods.html
|
81
|
-
http://opensource.symetrie.com/trac/better_nested_set/
|
82
|
-
|
83
|
-
== How to contribute
|
84
|
-
|
85
|
-
If you find what you might think is a bug:
|
86
|
-
|
87
|
-
1. Check the GitHub issue tracker to see if anyone else has had the same issue.
|
88
|
-
http://github.com/skyeagle/nested_set/issues/
|
89
|
-
2. If you don't see anything, create an issue with information on how to reproduce it.
|
90
|
-
|
91
|
-
If you want to contribute an enhancement or a fix:
|
92
|
-
|
93
|
-
1. Fork the project on github.
|
94
|
-
http://github.com/skyeagle/nested_set/
|
95
|
-
2. Make your changes with tests.
|
96
|
-
3. Commit the changes without making changes to the Rakefile, VERSION, or any other files that aren't related to your enhancement or fix
|
97
|
-
4. Send a pull request.
|
98
|
-
|
99
|
-
Copyright ©2010 Collective Idea, released under the MIT license
|