nested_set 1.5.4 → 1.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/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
|