closure_tree 4.4.0 → 4.5.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.
- checksums.yaml +5 -13
- data/.gitignore +12 -0
- data/.travis.yml +32 -0
- data/.yardopts +3 -0
- data/Appraisals +17 -0
- data/CHANGELOG.md +317 -0
- data/Gemfile +3 -0
- data/README.md +11 -8
- data/closure_tree.gemspec +35 -0
- data/gemfiles/activerecord_3.2.gemfile +9 -0
- data/gemfiles/activerecord_4.0.gemfile +8 -0
- data/gemfiles/activerecord_4.1.gemfile +8 -0
- data/gemfiles/activerecord_edge.gemfile +9 -0
- data/img/example.png +0 -0
- data/img/preorder.png +0 -0
- data/lib/closure_tree.rb +0 -2
- data/lib/closure_tree/acts_as_tree.rb +12 -0
- data/lib/closure_tree/digraphs.rb +2 -2
- data/lib/closure_tree/model.rb +22 -21
- data/lib/closure_tree/support.rb +1 -5
- data/lib/closure_tree/version.rb +1 -1
- data/mktree.rb +38 -0
- data/spec/db/database.yml +1 -1
- data/spec/hierarchy_maintenance_spec.rb +15 -0
- data/spec/label_spec.rb +23 -3
- data/spec/model_spec.rb +9 -0
- data/spec/parallel_prepend_sibling_spec.rb +2 -3
- data/spec/parallel_spec.rb +2 -8
- data/spec/spec_helper.rb +14 -7
- data/spec/uuid_tag_spec.rb +1 -1
- data/tests.sh +8 -0
- metadata +59 -40
checksums.yaml
CHANGED
|
@@ -1,15 +1,7 @@
|
|
|
1
1
|
---
|
|
2
|
-
|
|
3
|
-
metadata.gz:
|
|
4
|
-
|
|
5
|
-
data.tar.gz: !binary |-
|
|
6
|
-
ODAyOWI2MGYzOWM5N2Y0ZGU0ZTQ4OTQyNjYwYTAyYzFkNzhhYjdlYw==
|
|
2
|
+
SHA1:
|
|
3
|
+
metadata.gz: ceda99255848a84a4d3370654ecfad42dc2b7711
|
|
4
|
+
data.tar.gz: 71096e3755bb3dda8039eb49e3f301930ef7cc0d
|
|
7
5
|
SHA512:
|
|
8
|
-
metadata.gz:
|
|
9
|
-
|
|
10
|
-
YjhlN2IyNTA4YzE1N2MwZTMxNDEyNDhlYjQwOWNiYTU1ZDVlZTE0ODg2NWY1
|
|
11
|
-
NzUzN2ZmMjkwYTdmMjM0MmRkNmQ5YWQ2NTRkZWM5M2I0YzRmNTk=
|
|
12
|
-
data.tar.gz: !binary |-
|
|
13
|
-
NzdmMmIzNDMxMjc3OTA3MjMwODM2ZmE2NzhiNzgzNzAwMmU3NGY5MzEyMTNk
|
|
14
|
-
Njk1ZjA2MjBjMTQxOTRlYmIxZDAzMzMxNmRkZTBjNTZkNTMzNjgyNzEwZTRi
|
|
15
|
-
NTdiOTliYTU4NmM3YzdkMmVhOWI4ODJiNTMxYjc0NDI3MjI1Yzc=
|
|
6
|
+
metadata.gz: f40621b5ddc3cbc1c0de1959f2720b7f1e21e209ed7952878720cbcff981993037330a9c6f1e6f4f287e862b2af82e14b99109dde5a2330c6cb5e3256a0f7acb
|
|
7
|
+
data.tar.gz: ecd521d391c33e3afb162c25f8760c734dd58acec6c3a875d523ec7ec5dcfb50ccbbd7601f79d2fd68e2a1e592095174381508a8e45708dd91bcf1bd658cf0a7
|
data/.gitignore
ADDED
data/.travis.yml
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
language: ruby
|
|
2
|
+
rvm:
|
|
3
|
+
- 1.9.3
|
|
4
|
+
- 2.1.2
|
|
5
|
+
- ruby-head
|
|
6
|
+
# - rbx-2
|
|
7
|
+
|
|
8
|
+
gemfile:
|
|
9
|
+
- gemfiles/activerecord_3.2.gemfile
|
|
10
|
+
- gemfiles/activerecord_4.0.gemfile
|
|
11
|
+
- gemfiles/activerecord_4.1.gemfile
|
|
12
|
+
- gemfiles/activerecord_edge.gemfile
|
|
13
|
+
|
|
14
|
+
env:
|
|
15
|
+
- DB=sqlite
|
|
16
|
+
- DB=mysql
|
|
17
|
+
- DB=postgresql
|
|
18
|
+
|
|
19
|
+
script: WITH_ADVISORY_LOCK_PREFIX=$TRAVIS_JOB_ID bundle exec rake --trace all_spec_flavors
|
|
20
|
+
|
|
21
|
+
matrix:
|
|
22
|
+
fast_finish: true
|
|
23
|
+
allow_failures:
|
|
24
|
+
- gemfile: gemfiles/activerecord_edge.gemfile
|
|
25
|
+
- rvm: ruby-head
|
|
26
|
+
exclude:
|
|
27
|
+
- rvm: ruby-head
|
|
28
|
+
gemfile: gemfiles/activerecord_3.2.gemfile
|
|
29
|
+
- rvm: ruby-head
|
|
30
|
+
gemfile: gemfiles/activerecord_4.0.gemfile
|
|
31
|
+
- rvm: ruby-head
|
|
32
|
+
gemfile: gemfiles/activerecord_4.1.gemfile
|
data/.yardopts
ADDED
data/Appraisals
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
appraise "activerecord-3.2" do
|
|
2
|
+
gem 'activerecord', '~> 3.2'
|
|
3
|
+
gem 'strong_parameters'
|
|
4
|
+
end
|
|
5
|
+
|
|
6
|
+
appraise "activerecord-4.0" do
|
|
7
|
+
gem "activerecord", "~> 4.0"
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
appraise "activerecord-4.1" do
|
|
11
|
+
gem "activerecord", "~> 4.1"
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
appraise "activerecord-edge" do
|
|
15
|
+
gem "activerecord", github: "rails/rails"
|
|
16
|
+
gem 'arel', github: 'rails/arel'
|
|
17
|
+
end
|
data/CHANGELOG.md
ADDED
|
@@ -0,0 +1,317 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
### 4.5.0
|
|
4
|
+
|
|
5
|
+
* Merged a bunch of great changes from [Abdelkader Boudih](https://github.com/seuros),
|
|
6
|
+
including a change to use [appraisal](https://github.com/thoughtbot/appraisal)
|
|
7
|
+
* Added Travis builds for Rails 4.1.1 and Ruby 2.1.2
|
|
8
|
+
* Dropped support for Rails 3.1, as it is no longer receiving security patches.
|
|
9
|
+
See http://rubyonrails.org/security/ for more information.
|
|
10
|
+
|
|
11
|
+
### 4.4.0
|
|
12
|
+
|
|
13
|
+
* Added ```.self_and_descendant_ids``` and ```.self_and_ancestors_ids``` from [PR92](https://github.com/mceachen/closure_tree/pull/92).
|
|
14
|
+
Thanks, [Kir Shatrov](https://github.com/kirs)!
|
|
15
|
+
|
|
16
|
+
* Dropped support for Rails 3.0.
|
|
17
|
+
|
|
18
|
+
### 4.3.0
|
|
19
|
+
|
|
20
|
+
* Use [foreigner](https://github.com/matthuhiggins/foreigner) to prove that
|
|
21
|
+
things are inserted and deleted without violating foreign key constraints
|
|
22
|
+
|
|
23
|
+
* Added Rails 4.1.0.rc2 as a Travis CI build target
|
|
24
|
+
|
|
25
|
+
### 4.2.9
|
|
26
|
+
|
|
27
|
+
* Support for Heroku's cray assets:precompile hack for Rails 4.
|
|
28
|
+
Addresses [issue 78](https://github.com/mceachen/closure_tree/issues/78).
|
|
29
|
+
Thanks for the assist, [Alex Bowman](https://github.com/axlekb).
|
|
30
|
+
|
|
31
|
+
### 4.2.8
|
|
32
|
+
|
|
33
|
+
* More massaging for Rails 4 and ```attr_accessible``` support
|
|
34
|
+
|
|
35
|
+
### 4.2.7
|
|
36
|
+
|
|
37
|
+
* ```self_and_ancestors``` and ```ancestry_hierarchy``` are reloaded
|
|
38
|
+
when nodes are reparented. Addresses [issue 68](https://github.com/mceachen/closure_tree/issues/68).
|
|
39
|
+
Thanks for the assist, [Ivan Stana](https://github.com/istana).
|
|
40
|
+
|
|
41
|
+
### 4.2.6
|
|
42
|
+
|
|
43
|
+
* Explicitly added MIT licensing to the gemspec.
|
|
44
|
+
|
|
45
|
+
### 4.2.5
|
|
46
|
+
|
|
47
|
+
* Fix for potential deadlock from ```delete_hierarchy_references``` not being called within an
|
|
48
|
+
advisory lock. Thanks, [Armando Guereca](https://github.com/aguereca), for finding that!
|
|
49
|
+
|
|
50
|
+
* Sped up find_or_create_by_path to skip cycle detection validation.
|
|
51
|
+
A node whose ancestry was 200-deep took 20 seconds to create (!!), and now takes < 1 second.
|
|
52
|
+
|
|
53
|
+
* Fixed issue with MySQL that prevented nodes > 60 levels deep from being created
|
|
54
|
+
|
|
55
|
+
### 4.2.4
|
|
56
|
+
|
|
57
|
+
* Support for ```root?```, ```child?```, and proper parent-child associations
|
|
58
|
+
when both the parent and the child are not persisted. Addresses [issue 64](https://github.com/mceachen/closure_tree/issues/64).
|
|
59
|
+
Thanks for the help, [Gabriel Mazetto](https://github.com/brodock)!
|
|
60
|
+
|
|
61
|
+
### 4.2.3
|
|
62
|
+
|
|
63
|
+
* Fixed ```attr_accessible?``` error introduced in 4.2.2 ([issue 66](https://github.com/mceachen/closure_tree/issues/66)).
|
|
64
|
+
* Switched to use new WithAdvisoryLock::DatabaseAdapterSupport (in v0.0.9) to add Postgis support
|
|
65
|
+
|
|
66
|
+
### 4.2.2
|
|
67
|
+
|
|
68
|
+
* Support attr_accessible and strong_attributes even if you're on Rails 4
|
|
69
|
+
|
|
70
|
+
### 4.2.1
|
|
71
|
+
|
|
72
|
+
* Deleting from NumericDeterministicOrdering doesn't create sort order gaps anymore.
|
|
73
|
+
|
|
74
|
+
### 4.2.0
|
|
75
|
+
|
|
76
|
+
* Added ```with_ancestor(*ancestors)```. Thanks for the idea, [Matt](https://github.com/mgornick)!
|
|
77
|
+
* Applied [Leonel Galan](https://github.com/leonelgalan)'s fix for Strong Attribute support
|
|
78
|
+
* ```find_or_create_by``` now uses passed-in attributes as both selection and creation criteria.
|
|
79
|
+
Thanks for the help, [Judd Blair](https://github.com/juddblair)!
|
|
80
|
+
**Please note that this changes prior behavior—test your code with this new version!**
|
|
81
|
+
* ```ct_advisory_lock``` was moved into the ```_ct``` support class, to reduce model method pollution
|
|
82
|
+
* Moved a bunch of code into more focused piles of module mixins
|
|
83
|
+
|
|
84
|
+
### 4.1.0
|
|
85
|
+
|
|
86
|
+
* Added support for Rails 4.0.0.rc1 and Ruby 2.0.0 (while maintaining backward compatibility with Rails 3, BOOYA)
|
|
87
|
+
* Added ```#to_dot_digraph```, suitable for Graphviz rendering
|
|
88
|
+
|
|
89
|
+
### 4.0.1
|
|
90
|
+
|
|
91
|
+
* Numeric, deterministically ordered siblings will always be [0..#{self_and_siblings.count}]
|
|
92
|
+
(previously, the sort order might use negative values, which broke the preordering).
|
|
93
|
+
Resolves [issue 49](https://github.com/mceachen/closure_tree/issues/49). Thanks for the help,
|
|
94
|
+
[Leonel Galan](https://github.com/leonelgalan), [Juan Hoyos](https://github.com/elhoyos), and
|
|
95
|
+
[Michael Elfassy](https://github.com/elfassy)!
|
|
96
|
+
|
|
97
|
+
* The ```order``` option can be a symbol now. Resolves [issue 46](https://github.com/mceachen/closure_tree/issues/46).
|
|
98
|
+
|
|
99
|
+
### 4.0.0
|
|
100
|
+
|
|
101
|
+
* Moved all of closure_tree's implementation-detail methods into a ```ClosureTree::Support```
|
|
102
|
+
instance, which removes almost all of the namespace pollution in your models that wasn't
|
|
103
|
+
for normal consumption. If you were using any of these methods, they're now available through
|
|
104
|
+
the "_ct" class and instance member.
|
|
105
|
+
|
|
106
|
+
*This change may break consumers*, so I incremented the major version number, even though no new
|
|
107
|
+
functionality was released.
|
|
108
|
+
|
|
109
|
+
### 3.10.2
|
|
110
|
+
|
|
111
|
+
* Prevent faulty SQL statement when ```#siblings``` is called on an unsaved records.
|
|
112
|
+
Resolves [issue 52](https://github.com/mceachen/closure_tree/pull/52). Perfect pull
|
|
113
|
+
request by [Gary Greyling](https://github.com/garygreyling).
|
|
114
|
+
|
|
115
|
+
* The ```.roots``` class method now correctly respects the ```:order``` option.
|
|
116
|
+
Resolves [issue 53](https://github.com/mceachen/closure_tree/issues/53).
|
|
117
|
+
Thanks for finding this, [Brendon Muir](https://github.com/brendon)!
|
|
118
|
+
|
|
119
|
+
### 3.10.1
|
|
120
|
+
|
|
121
|
+
* Multipart constant names like "Admin::PageHierarchy" are now supported.
|
|
122
|
+
Resolves [issue 47](https://github.com/mceachen/closure_tree/issues/47).
|
|
123
|
+
Thanks for the perfect pull request, [Simon Menke](https://github.com/fd)!
|
|
124
|
+
|
|
125
|
+
* Committing transactions involving large numbers of hierarchy model classes was very slow due
|
|
126
|
+
to hash collisions in the hierarchy class. A better hash implementation addressed
|
|
127
|
+
[issue 48](https://github.com/mceachen/closure_tree/issues/48).
|
|
128
|
+
Thanks, [Joel Turkel](https://github.com/jturkel)!
|
|
129
|
+
|
|
130
|
+
### 3.10.0
|
|
131
|
+
|
|
132
|
+
* Added ```#roots_and_descendants_preordered```.
|
|
133
|
+
Thanks for the suggestion, [Leonel Galan](https://github.com/leonelgalan)!
|
|
134
|
+
|
|
135
|
+
### 3.9.0
|
|
136
|
+
|
|
137
|
+
* Added ```.child_ids```.
|
|
138
|
+
* Removed ```dependent => destroy``` on the descendant_hierarchy and ancestor_hierarchy collections
|
|
139
|
+
(they were a mistake).
|
|
140
|
+
* Clarified documentation for creation and child associations.
|
|
141
|
+
Because ```Tag.create!(:parent => ...)``` requires a ```.reload```, I removed it as an example.
|
|
142
|
+
|
|
143
|
+
All three of these improvements were suggested by Andrew Bromwich. Thanks!
|
|
144
|
+
|
|
145
|
+
### 3.8.2
|
|
146
|
+
|
|
147
|
+
* find_by_path uses 1 SELECT now. BOOM.
|
|
148
|
+
|
|
149
|
+
### 3.8.1
|
|
150
|
+
|
|
151
|
+
* Double-check locking for find_or_create_by_path
|
|
152
|
+
|
|
153
|
+
### 3.8.0
|
|
154
|
+
|
|
155
|
+
* Support for preordered descendants. This requires a numeric sort order column.
|
|
156
|
+
Resolves [feature request 38](https://github.com/mceachen/closure_tree/issues/38).
|
|
157
|
+
* Moved modules from ```acts_as_tree``` into separate files
|
|
158
|
+
|
|
159
|
+
### 3.7.3
|
|
160
|
+
|
|
161
|
+
Due to MySQL's inability to lock rows properly, I've switched to advisory_locks for
|
|
162
|
+
all write paths. This will prevent deadlocks, addressing
|
|
163
|
+
[issue 41](https://github.com/mceachen/closure_tree/issues/41).
|
|
164
|
+
|
|
165
|
+
### 3.7.2
|
|
166
|
+
|
|
167
|
+
* Support for UUID primary keys. Addresses
|
|
168
|
+
[issue 40](https://github.com/mceachen/closure_tree/issues/40). Thanks for the pull request,
|
|
169
|
+
[Julien](https://github.com/calexicoz)!
|
|
170
|
+
|
|
171
|
+
### 3.7.1
|
|
172
|
+
|
|
173
|
+
* Moved requires into ActiveSupport.on_load
|
|
174
|
+
* Added ```require 'with_advisory_lock'```
|
|
175
|
+
|
|
176
|
+
### 3.7.0
|
|
177
|
+
|
|
178
|
+
**Thread safety!**
|
|
179
|
+
* [Advisory locks](https://github.com/mceachen/with_advisory_lock) were
|
|
180
|
+
integrated with the class-level ```find_or_create_by_path``` and ```rebuild!```.
|
|
181
|
+
* Pessimistic locking is used by the instance-level ```find_or_create_by_path```.
|
|
182
|
+
|
|
183
|
+
### 3.6.9
|
|
184
|
+
|
|
185
|
+
* [Don Morrison](https://github.com/elskwid) massaged the [#hash_tree](#nested-hashes) query to
|
|
186
|
+
be more efficient, and found a bug in ```hash_tree```'s query that resulted in duplicate rows,
|
|
187
|
+
wasting time on the ruby side.
|
|
188
|
+
|
|
189
|
+
### 3.6.7
|
|
190
|
+
|
|
191
|
+
* Added workaround for ActiveRecord::Observer usage pre-db-creation. Addresses
|
|
192
|
+
[issue 32](https://github.com/mceachen/closure_tree/issues/32).
|
|
193
|
+
Thanks, [Don Morrison](https://github.com/elskwid)!
|
|
194
|
+
|
|
195
|
+
### 3.6.6
|
|
196
|
+
|
|
197
|
+
* Added support for Rails 4's [strong parameter](https://github.com/rails/strong_parameters).
|
|
198
|
+
Thanks, [James Miller](https://github.com/bensie)!
|
|
199
|
+
|
|
200
|
+
### 3.6.5
|
|
201
|
+
|
|
202
|
+
* Use ```quote_table_name``` instead of ```quote_column_name```. Addresses
|
|
203
|
+
[issue 29](https://github.com/mceachen/closure_tree/issues/29). Thanks,
|
|
204
|
+
[Marcello Barnaba](https://github.com/vjt)!
|
|
205
|
+
|
|
206
|
+
### 3.6.4
|
|
207
|
+
|
|
208
|
+
* Use ```.pluck``` when available for ```.ids_from```. Addresses
|
|
209
|
+
[issue 26](https://github.com/mceachen/closure_tree/issues/26). Thanks,
|
|
210
|
+
[Chris Sturgill](https://github.com/sturgill)!
|
|
211
|
+
|
|
212
|
+
### 3.6.3
|
|
213
|
+
|
|
214
|
+
* Fixed [issue 24](https://github.com/mceachen/closure_tree/issues/24), which optimized ```#hash_tree```
|
|
215
|
+
for roots. Thanks, [Saverio Trioni](https://github.com/rewritten)!
|
|
216
|
+
|
|
217
|
+
### 3.6.2
|
|
218
|
+
|
|
219
|
+
* Fixed [issue 23](https://github.com/mceachen/closure_tree/issues/23), which added support for ```#siblings```
|
|
220
|
+
when sort_order wasn't specified. Thanks, [Gary Greyling](https://github.com/garygreyling)!
|
|
221
|
+
|
|
222
|
+
### 3.6.1
|
|
223
|
+
|
|
224
|
+
* Fixed [issue 20](https://github.com/mceachen/closure_tree/issues/20), which affected
|
|
225
|
+
deterministic ordering when siblings where different STI classes. Thanks, [edwinramirez](https://github.com/edwinramirez)!
|
|
226
|
+
|
|
227
|
+
### 3.6.0
|
|
228
|
+
|
|
229
|
+
Added support for:
|
|
230
|
+
* ```:hierarchy_class_name``` as an option
|
|
231
|
+
* ActiveRecord::Base.table_name_prefix
|
|
232
|
+
* ActiveRecord::Base.table_name_suffix
|
|
233
|
+
|
|
234
|
+
This addresses [issue 21](https://github.com/mceachen/closure_tree/issues/21). Thanks, [Judd Blair](https://github.com/juddblair)!
|
|
235
|
+
|
|
236
|
+
### 3.5.2
|
|
237
|
+
|
|
238
|
+
* Added ```find_all_by_generation```
|
|
239
|
+
for [feature request 17](https://github.com/mceachen/closure_tree/issues/17).
|
|
240
|
+
|
|
241
|
+
### 3.4.2
|
|
242
|
+
|
|
243
|
+
* Fixed [issue 18](https://github.com/mceachen/closure_tree/issues/18), which affected
|
|
244
|
+
append_node/prepend_node ordering when the first node didn't have an explicit order_by value
|
|
245
|
+
|
|
246
|
+
### 3.4.1
|
|
247
|
+
|
|
248
|
+
* Reverted .gemspec mistake that changed add_development_dependency to add_runtime_dependency
|
|
249
|
+
|
|
250
|
+
### 3.4.0
|
|
251
|
+
|
|
252
|
+
Fixed [issue 15](https://github.com/mceachen/closure_tree/issues/15):
|
|
253
|
+
* "parent" is now attr_accessible, which adds support for constructor-provided parents.
|
|
254
|
+
* updated readme accordingly
|
|
255
|
+
|
|
256
|
+
### 3.3.2
|
|
257
|
+
|
|
258
|
+
* Merged calebphillips' patch for a more efficient leaves query
|
|
259
|
+
|
|
260
|
+
### 3.3.1
|
|
261
|
+
|
|
262
|
+
* Added support for partially-unsaved hierarchies [issue 13](https://github.com/mceachen/closure_tree/issues/13):
|
|
263
|
+
```
|
|
264
|
+
a = Tag.new(name: "a")
|
|
265
|
+
b = Tag.new(name: "b")
|
|
266
|
+
a.children << b
|
|
267
|
+
a.save
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
### 3.3.0
|
|
271
|
+
|
|
272
|
+
* Added [```hash_tree```](#nested-hashes).
|
|
273
|
+
|
|
274
|
+
### 3.2.1
|
|
275
|
+
|
|
276
|
+
* Added ```ancestor_ids```, ```descendant_ids```, and ```sibling_ids```
|
|
277
|
+
* Added example spec to solve [issue 9](https://github.com/mceachen/closure_tree/issues/9)
|
|
278
|
+
|
|
279
|
+
### 3.2.0
|
|
280
|
+
|
|
281
|
+
* Added support for deterministic ordering of nodes.
|
|
282
|
+
|
|
283
|
+
### 3.1.0
|
|
284
|
+
|
|
285
|
+
* Switched to using ```has_many :though``` rather than ```has_and_belongs_to_many```
|
|
286
|
+
|
|
287
|
+
### 3.0.4
|
|
288
|
+
|
|
289
|
+
* Merged [pull request](https://github.com/mceachen/closure_tree/pull/8) to fix ```.siblings``` and ```.self_and_siblings```
|
|
290
|
+
(Thanks, [eljojo](https://github.com/eljojo)!)
|
|
291
|
+
|
|
292
|
+
### 3.0.3
|
|
293
|
+
|
|
294
|
+
* Added support for ActiveRecord's whitelist_attributes
|
|
295
|
+
(Make sure you read [the Rails Security Guide](http://guides.rubyonrails.org/security.html), and
|
|
296
|
+
enable ```config.active_record.whitelist_attributes``` in your ```config/application.rb``` ASAP!)
|
|
297
|
+
|
|
298
|
+
### 3.0.2
|
|
299
|
+
|
|
300
|
+
* Fix for ancestry-loop detection (performed by a validation, not through raising an exception in before_save)
|
|
301
|
+
|
|
302
|
+
### 3.0.1
|
|
303
|
+
|
|
304
|
+
* Support 3.2.0's fickle deprecation of InstanceMethods (Thanks, [jheiss](https://github.com/mceachen/closure_tree/pull/5))!
|
|
305
|
+
|
|
306
|
+
### 3.0.0
|
|
307
|
+
|
|
308
|
+
* Support for polymorphic trees
|
|
309
|
+
* ```find_by_path``` and ```find_or_create_by_path``` signatures changed to support constructor attributes
|
|
310
|
+
* tested against Rails 3.1.3
|
|
311
|
+
|
|
312
|
+
### 2.0.0
|
|
313
|
+
|
|
314
|
+
* Had to increment the major version, as rebuild! will need to be called by prior consumers to support the new ```leaves``` class and instance methods.
|
|
315
|
+
* Tag deletion is supported now along with ```:dependent => :destroy``` and ```:dependent => :delete_all```
|
|
316
|
+
* Switched from default rails plugin directory structure to rspec
|
|
317
|
+
* Support for running specs under different database engines: ```export DB ; for DB in sqlite3 mysql postgresql ; do rake ; done```
|
data/Gemfile
ADDED
data/README.md
CHANGED
|
@@ -25,7 +25,7 @@ closure_tree has some great features:
|
|
|
25
25
|
* __Best-in-class mutation performance__:
|
|
26
26
|
* 2 SQL INSERTs on node creation
|
|
27
27
|
* 3 SQL INSERT/UPDATEs on node reparenting
|
|
28
|
-
* __Support for Rails 3.
|
|
28
|
+
* __Support for Rails 3.2, 4.0, and 4.1__
|
|
29
29
|
* Support for reparenting children (and all their descendants)
|
|
30
30
|
* Support for [concurrency](#concurrency) (using [with_advisory_lock](https://github.com/mceachen/with_advisory_lock))
|
|
31
31
|
* Support for polymorphism [STI](#sti) within the hierarchy
|
|
@@ -53,7 +53,7 @@ for a description of different tree storage algorithms.
|
|
|
53
53
|
|
|
54
54
|
## Installation
|
|
55
55
|
|
|
56
|
-
Note that closure_tree only supports Rails 3.
|
|
56
|
+
Note that closure_tree only supports Rails 3.2 and later, and has test coverage for MySQL, PostgreSQL, and SQLite.
|
|
57
57
|
|
|
58
58
|
1. Add this to your Gemfile: ```gem 'closure_tree'```
|
|
59
59
|
|
|
@@ -243,7 +243,7 @@ Just for kicks, this is the test tree I used for proving that preordered tree tr
|
|
|
243
243
|
When you include ```acts_as_tree``` in your model, you can provide a hash to override the following defaults:
|
|
244
244
|
|
|
245
245
|
* ```:parent_column_name``` to override the column name of the parent foreign key in the model's table. This defaults to "parent_id".
|
|
246
|
-
* ```:
|
|
246
|
+
* ```:hierarchy_class_name``` to override the hierarchy class name. This defaults to the singular name of the model + "Hierarchy", like ```TagHierarchy```.
|
|
247
247
|
* ```:hierarchy_table_name``` to override the hierarchy table name. This defaults to the singular name of the model + "_hierarchies", like ```tag_hierarchies```.
|
|
248
248
|
* ```:dependent``` determines what happens when a node is destroyed. Defaults to ```nullify```.
|
|
249
249
|
* ```:nullify``` will simply set the parent column to null. Each child node will be considered a "root" node. This is the default.
|
|
@@ -437,6 +437,10 @@ database with multiple threads, and don't provide an alternative mutex.
|
|
|
437
437
|
|
|
438
438
|
## FAQ
|
|
439
439
|
|
|
440
|
+
### Does this work well with ```#default_scope```?
|
|
441
|
+
|
|
442
|
+
No. Please see [issue 86](https://github.com/mceachen/closure_tree/issues/86) for details.
|
|
443
|
+
|
|
440
444
|
### Does this gem support multiple parents?
|
|
441
445
|
|
|
442
446
|
No. This gem's API is based on the assumption that each node has either 0 or 1 parent.
|
|
@@ -484,15 +488,14 @@ end
|
|
|
484
488
|
|
|
485
489
|
Closure tree is [tested under every valid combination](http://travis-ci.org/#!/mceachen/closure_tree) of
|
|
486
490
|
|
|
487
|
-
* Ruby 1.9.3
|
|
488
|
-
*
|
|
489
|
-
*
|
|
491
|
+
* Ruby 1.9.3 , 2.0.0 and 2.1.2
|
|
492
|
+
* Rubinius 2.2.6
|
|
493
|
+
* The latest Rails 3.2, 4.0, 4.1 and master branches
|
|
494
|
+
* Concurrency tests for MySQL and PostgreSQL. SQLite works in a single-threaded environment.
|
|
490
495
|
|
|
491
496
|
Assuming you're using [rbenv](https://github.com/sstephenson/rbenv), you can use ```tests.sh``` to
|
|
492
497
|
run the test matrix locally.
|
|
493
498
|
|
|
494
|
-
Parallelism is not tested with Rails 3.1.x due to this [known issue](https://github.com/rails/rails/issues/7538).
|
|
495
|
-
|
|
496
499
|
## Change log
|
|
497
500
|
|
|
498
501
|
See https://github.com/mceachen/closure_tree/blob/master/CHANGELOG.md
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
$LOAD_PATH.push File.expand_path('../lib', __FILE__)
|
|
2
|
+
require 'closure_tree/version'
|
|
3
|
+
|
|
4
|
+
Gem::Specification.new do |gem|
|
|
5
|
+
gem.name = 'closure_tree'
|
|
6
|
+
gem.version = ::ClosureTree::VERSION
|
|
7
|
+
gem.authors = ['Matthew McEachen']
|
|
8
|
+
gem.email = ['matthew-github@mceachen.org']
|
|
9
|
+
gem.homepage = 'http://mceachen.github.io/closure_tree/'
|
|
10
|
+
|
|
11
|
+
gem.summary = %q(Easily and efficiently make your ActiveRecord model support hierarchies)
|
|
12
|
+
gem.description = gem.summary
|
|
13
|
+
gem.license = 'MIT'
|
|
14
|
+
|
|
15
|
+
gem.files = `git ls-files`.split($INPUT_RECORD_SEPARATOR)
|
|
16
|
+
gem.test_files = gem.files.grep(%r{^spec/})
|
|
17
|
+
|
|
18
|
+
gem.add_runtime_dependency 'activerecord', '>= 3.2.0'
|
|
19
|
+
gem.add_runtime_dependency 'with_advisory_lock', '>= 0.0.9' # <- to prevent duplicate roots
|
|
20
|
+
|
|
21
|
+
gem.add_development_dependency 'rake'
|
|
22
|
+
gem.add_development_dependency 'yard'
|
|
23
|
+
gem.add_development_dependency 'rspec'
|
|
24
|
+
gem.add_development_dependency 'rspec-instafail'
|
|
25
|
+
gem.add_development_dependency 'rspec-rails' # FIXME: for rspec-rails and rspec fixture support
|
|
26
|
+
gem.add_development_dependency 'mysql2'
|
|
27
|
+
gem.add_development_dependency 'pg'
|
|
28
|
+
gem.add_development_dependency 'sqlite3'
|
|
29
|
+
gem.add_development_dependency 'uuidtools'
|
|
30
|
+
gem.add_development_dependency 'database_cleaner'
|
|
31
|
+
gem.add_development_dependency 'appraisal'
|
|
32
|
+
|
|
33
|
+
# gem.add_development_dependency 'ruby-prof' # <- don't need this normally.
|
|
34
|
+
# TODO: gem 'activerecord-jdbcsqlite3-adapter', :platform => :jruby
|
|
35
|
+
end
|
data/img/example.png
ADDED
|
Binary file
|
data/img/preorder.png
ADDED
|
Binary file
|
data/lib/closure_tree.rb
CHANGED
|
@@ -11,6 +11,18 @@ require 'closure_tree/numeric_deterministic_ordering'
|
|
|
11
11
|
module ClosureTree
|
|
12
12
|
module ActsAsTree
|
|
13
13
|
def acts_as_tree(options = {})
|
|
14
|
+
options.assert_valid_keys(
|
|
15
|
+
:base_class,
|
|
16
|
+
:dependent,
|
|
17
|
+
:hierarchy_class_name,
|
|
18
|
+
:hierarchy_table_name,
|
|
19
|
+
:name,
|
|
20
|
+
:name_column,
|
|
21
|
+
:order,
|
|
22
|
+
:parent_column_name,
|
|
23
|
+
:with_advisory_lock
|
|
24
|
+
)
|
|
25
|
+
|
|
14
26
|
class_attribute :_ct
|
|
15
27
|
self._ct = ClosureTree::Support.new(self, options)
|
|
16
28
|
|
|
@@ -14,11 +14,11 @@ module ClosureTree
|
|
|
14
14
|
module ClassMethods
|
|
15
15
|
# Renders the given scope as a DOT digraph, suitable for rendering by Graphviz
|
|
16
16
|
def to_dot_digraph(tree_scope)
|
|
17
|
-
id_to_instance = tree_scope.
|
|
17
|
+
id_to_instance = tree_scope.reduce({}) { |h, ea| h[ea.id] = ea; h }
|
|
18
18
|
output = StringIO.new
|
|
19
19
|
output << "digraph G {\n"
|
|
20
20
|
tree_scope.each do |ea|
|
|
21
|
-
if id_to_instance.
|
|
21
|
+
if id_to_instance.key? ea._ct_parent_id
|
|
22
22
|
output << " #{ea._ct_parent_id} -> #{ea._ct_id}\n"
|
|
23
23
|
end
|
|
24
24
|
output << " #{ea._ct_id} [label=\"#{ea.to_digraph_label}\"]\n"
|
data/lib/closure_tree/model.rb
CHANGED
|
@@ -6,39 +6,40 @@ module ClosureTree
|
|
|
6
6
|
|
|
7
7
|
included do
|
|
8
8
|
belongs_to :parent,
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
9
|
+
class_name: _ct.model_class.to_s,
|
|
10
|
+
foreign_key: _ct.parent_column_name,
|
|
11
|
+
inverse_of: :children
|
|
12
12
|
|
|
13
|
+
# TODO, remove when activerecord 3.2 support is dropped
|
|
13
14
|
attr_accessible :parent if _ct.use_attr_accessible?
|
|
14
15
|
|
|
15
16
|
order_by_generations = "#{_ct.quoted_hierarchy_table_name}.generations asc"
|
|
16
17
|
|
|
17
18
|
has_many :children, *_ct.has_many_with_order_option(
|
|
18
|
-
:
|
|
19
|
-
:
|
|
20
|
-
:
|
|
21
|
-
:
|
|
19
|
+
class_name: _ct.model_class.to_s,
|
|
20
|
+
foreign_key: _ct.parent_column_name,
|
|
21
|
+
dependent: _ct.options[:dependent],
|
|
22
|
+
inverse_of: :parent)
|
|
22
23
|
|
|
23
24
|
has_many :ancestor_hierarchies, *_ct.has_many_without_order_option(
|
|
24
|
-
:
|
|
25
|
-
:
|
|
26
|
-
:
|
|
25
|
+
class_name: _ct.hierarchy_class_name,
|
|
26
|
+
foreign_key: 'descendant_id',
|
|
27
|
+
order: order_by_generations)
|
|
27
28
|
|
|
28
29
|
has_many :self_and_ancestors, *_ct.has_many_without_order_option(
|
|
29
|
-
:
|
|
30
|
-
:
|
|
31
|
-
:
|
|
30
|
+
through: :ancestor_hierarchies,
|
|
31
|
+
source: :ancestor,
|
|
32
|
+
order: order_by_generations)
|
|
32
33
|
|
|
33
34
|
has_many :descendant_hierarchies, *_ct.has_many_without_order_option(
|
|
34
|
-
:
|
|
35
|
-
:
|
|
36
|
-
:
|
|
35
|
+
class_name: _ct.hierarchy_class_name,
|
|
36
|
+
foreign_key: 'ancestor_id',
|
|
37
|
+
order: order_by_generations)
|
|
37
38
|
|
|
38
39
|
has_many :self_and_descendants, *_ct.has_many_with_order_option(
|
|
39
|
-
:
|
|
40
|
-
:
|
|
41
|
-
:
|
|
40
|
+
through: :descendant_hierarchies,
|
|
41
|
+
source: :descendant,
|
|
42
|
+
order: order_by_generations)
|
|
42
43
|
end
|
|
43
44
|
|
|
44
45
|
# Delegate to the Support instance on the class:
|
|
@@ -76,7 +77,7 @@ module ClosureTree
|
|
|
76
77
|
ancestors.size
|
|
77
78
|
end
|
|
78
79
|
|
|
79
|
-
|
|
80
|
+
alias_method :level, :depth
|
|
80
81
|
|
|
81
82
|
def ancestors
|
|
82
83
|
without_self(self_and_ancestors)
|
|
@@ -94,7 +95,7 @@ module ClosureTree
|
|
|
94
95
|
# to the +name_column+.
|
|
95
96
|
# (so child.ancestry_path == +%w{grandparent parent child}+
|
|
96
97
|
def ancestry_path(to_s_column = _ct.name_column)
|
|
97
|
-
self_and_ancestors.reverse.
|
|
98
|
+
self_and_ancestors.reverse.map { |n| n.send to_s_column.to_sym }
|
|
98
99
|
end
|
|
99
100
|
|
|
100
101
|
def child_ids
|
data/lib/closure_tree/support.rb
CHANGED
|
@@ -103,11 +103,7 @@ module ClosureTree
|
|
|
103
103
|
end
|
|
104
104
|
|
|
105
105
|
def ids_from(scope)
|
|
106
|
-
|
|
107
|
-
scope.pluck(model_class.primary_key)
|
|
108
|
-
else
|
|
109
|
-
scope.select(model_class.primary_key).map { |ea| ea._ct_id }
|
|
110
|
-
end
|
|
106
|
+
scope.pluck(model_class.primary_key)
|
|
111
107
|
end
|
|
112
108
|
|
|
113
109
|
def with_advisory_lock(&block)
|
data/lib/closure_tree/version.rb
CHANGED
data/mktree.rb
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
#!/usr/bin/env bundle exec ruby -I lib:spec
|
|
2
|
+
|
|
3
|
+
# Simple benchmark utility to create a closure tree based on the topology of the current filesystem
|
|
4
|
+
|
|
5
|
+
#ENV['NONUKES'] = '1'
|
|
6
|
+
require 'spec_helper'
|
|
7
|
+
require 'findler'
|
|
8
|
+
require 'pathname'
|
|
9
|
+
|
|
10
|
+
# Returns the current path, split into an array.
|
|
11
|
+
# Pathname.new("/a/b/c").path_array = ["a", "b", "c"]
|
|
12
|
+
class Pathname
|
|
13
|
+
def path_array
|
|
14
|
+
a = []
|
|
15
|
+
each_filename { |ea| a << ea }
|
|
16
|
+
a
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
cnt = 0
|
|
21
|
+
f = Findler.new '/'
|
|
22
|
+
iter = f.iterator
|
|
23
|
+
Tag.with_advisory_lock('closure_tree') do
|
|
24
|
+
while (nxt = iter.next_file) && ((cnt += 1) < 1000)
|
|
25
|
+
t = Tag.find_or_create_by_path(nxt.path_array)
|
|
26
|
+
puts "created #{nxt.to_s}"
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
puts "Tag.all.size: #{Tag.all.size}"
|
|
31
|
+
puts "TagHierarchy.all.size: #{TagHierarchy.all.size}"
|
|
32
|
+
|
|
33
|
+
puts 'Tag.roots performance:'
|
|
34
|
+
puts Benchmark.measure { Tag.roots.size }
|
|
35
|
+
|
|
36
|
+
puts 'Tag.leaves performance:'
|
|
37
|
+
puts Benchmark.measure { Tag.leaves.size }
|
|
38
|
+
|
data/spec/db/database.yml
CHANGED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
describe ClosureTree::HierarchyMaintenance do
|
|
4
|
+
describe '.rebuild!' do
|
|
5
|
+
it 'rebuild tree' do
|
|
6
|
+
20.times do |counter|
|
|
7
|
+
Metal.create(:value => "Nitro-#{counter}", parent: Metal.all.sample)
|
|
8
|
+
end
|
|
9
|
+
hierarchy_count = MetalHierarchy.count
|
|
10
|
+
MetalHierarchy.delete_all
|
|
11
|
+
Metal.rebuild!
|
|
12
|
+
expect(MetalHierarchy.count).to eq(hierarchy_count)
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
data/spec/label_spec.rb
CHANGED
|
@@ -49,9 +49,7 @@ describe Label do
|
|
|
49
49
|
b = c.parent
|
|
50
50
|
a = c.root
|
|
51
51
|
a.destroy
|
|
52
|
-
Label.exists?(a).should be_false
|
|
53
|
-
Label.exists?(b).should be_false
|
|
54
|
-
Label.exists?(c).should be_false
|
|
52
|
+
Label.exists?(id: [a.id,b.id,c.id]).should be_false
|
|
55
53
|
end
|
|
56
54
|
end
|
|
57
55
|
|
|
@@ -346,6 +344,28 @@ describe Label do
|
|
|
346
344
|
end
|
|
347
345
|
end
|
|
348
346
|
|
|
347
|
+
context "descendent destruction" do
|
|
348
|
+
it "properly destroys descendents created with add_child" do
|
|
349
|
+
a = Label.create(name: 'a')
|
|
350
|
+
b = Label.new(name: 'b')
|
|
351
|
+
a.add_child b
|
|
352
|
+
c = Label.new(name: 'c')
|
|
353
|
+
b.add_child c
|
|
354
|
+
a.destroy
|
|
355
|
+
Label.exists?(id: [a.id,b.id,c.id]).should be_false
|
|
356
|
+
end
|
|
357
|
+
|
|
358
|
+
it "properly destroys descendents created with <<" do
|
|
359
|
+
a = Label.create(name: 'a')
|
|
360
|
+
b = Label.new(name: 'b')
|
|
361
|
+
a.children << b
|
|
362
|
+
c = Label.new(name: 'c')
|
|
363
|
+
b.children << c
|
|
364
|
+
a.destroy
|
|
365
|
+
Label.exists?(id: [a.id,b.id,c.id]).should be_false
|
|
366
|
+
end
|
|
367
|
+
end
|
|
368
|
+
|
|
349
369
|
context "preorder" do
|
|
350
370
|
it "returns descendants in proper order" do
|
|
351
371
|
create_preorder_tree
|
data/spec/model_spec.rb
ADDED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
require 'spec_helper'
|
|
2
2
|
require 'securerandom'
|
|
3
3
|
|
|
4
|
-
describe "threadhot" do
|
|
4
|
+
describe "threadhot", concurrency: true do
|
|
5
5
|
|
|
6
6
|
before :each do
|
|
7
7
|
@iterations = 5
|
|
@@ -39,5 +39,4 @@ describe "threadhot" do
|
|
|
39
39
|
Label.all.select { |ea| ea.root? }.should == [@target.parent]
|
|
40
40
|
end
|
|
41
41
|
|
|
42
|
-
|
|
43
|
-
end if ((ENV["DB"] != "sqlite") && (ActiveRecord::VERSION::STRING =~ /^3.2/))
|
|
42
|
+
end
|
data/spec/parallel_spec.rb
CHANGED
|
@@ -1,11 +1,5 @@
|
|
|
1
1
|
require 'spec_helper'
|
|
2
2
|
|
|
3
|
-
parallelism_is_broken = begin
|
|
4
|
-
# Rails < 3.2 has known bugs with parallelism
|
|
5
|
-
(ActiveRecord::VERSION::MAJOR <= 3 && ActiveRecord::VERSION::MINOR < 2) ||
|
|
6
|
-
# SQLite doesn't support parallel writes
|
|
7
|
-
ENV["DB"] =~ /sqlite/
|
|
8
|
-
end
|
|
9
3
|
|
|
10
4
|
class DbThread
|
|
11
5
|
def initialize(&block)
|
|
@@ -19,7 +13,7 @@ class DbThread
|
|
|
19
13
|
end
|
|
20
14
|
end
|
|
21
15
|
|
|
22
|
-
describe "threadhot" do
|
|
16
|
+
describe "threadhot", concurrency: true do
|
|
23
17
|
|
|
24
18
|
before :each do
|
|
25
19
|
@parent = nil
|
|
@@ -144,4 +138,4 @@ describe "threadhot" do
|
|
|
144
138
|
User.all.should be_empty
|
|
145
139
|
end
|
|
146
140
|
|
|
147
|
-
end
|
|
141
|
+
end
|
data/spec/spec_helper.rb
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
$:.unshift(File.dirname(__FILE__) + '/../lib')
|
|
2
2
|
plugin_test_dir = File.dirname(__FILE__)
|
|
3
3
|
|
|
4
|
-
|
|
4
|
+
|
|
5
5
|
ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__)
|
|
6
6
|
require 'bundler/setup' if File.exists?(ENV['BUNDLE_GEMFILE'])
|
|
7
7
|
require 'rspec'
|
|
@@ -17,8 +17,7 @@ if ENV['STDOUT_LOGGING']
|
|
|
17
17
|
ActiveRecord::Base.logger = log
|
|
18
18
|
end
|
|
19
19
|
|
|
20
|
-
|
|
21
|
-
require 'erb'
|
|
20
|
+
|
|
22
21
|
ENV["DB"] ||= "mysql"
|
|
23
22
|
ActiveRecord::Base.table_name_prefix = ENV['DB_PREFIX'].to_s
|
|
24
23
|
ActiveRecord::Base.table_name_suffix = ENV['DB_SUFFIX'].to_s
|
|
@@ -32,20 +31,19 @@ ActiveRecord::Base.configurations = YAML::load(ERB.new(IO.read(plugin_test_dir +
|
|
|
32
31
|
|
|
33
32
|
def recreate_db
|
|
34
33
|
db_name = ActiveRecord::Base.configurations[ENV["DB"]]["database"]
|
|
35
|
-
case ENV['DB']
|
|
34
|
+
case ENV['DB']
|
|
36
35
|
when 'sqlite'
|
|
37
|
-
File.delete 'spec/sqlite3.db' if File.exist? 'spec/sqlite3.db'
|
|
38
36
|
when 'postgresql'
|
|
39
37
|
`psql -c 'DROP DATABASE #{db_name}' -U postgres`
|
|
40
38
|
`psql -c 'CREATE DATABASE #{db_name}' -U postgres`
|
|
41
|
-
|
|
39
|
+
else
|
|
42
40
|
`mysql -e 'DROP DATABASE IF EXISTS #{db_name}'`
|
|
43
41
|
`mysql -e 'CREATE DATABASE #{db_name}'`
|
|
44
42
|
end
|
|
45
43
|
ActiveRecord::Base.connection.reconnect!
|
|
46
44
|
end
|
|
47
45
|
|
|
48
|
-
ActiveRecord::Base.establish_connection(ENV["DB"])
|
|
46
|
+
ActiveRecord::Base.establish_connection(ENV["DB"].to_sym)
|
|
49
47
|
|
|
50
48
|
ActiveRecord::Migration.verbose = false
|
|
51
49
|
if ENV['NONUKES']
|
|
@@ -86,6 +84,12 @@ Thread.abort_on_exception = true
|
|
|
86
84
|
|
|
87
85
|
DatabaseCleaner.strategy = :truncation
|
|
88
86
|
|
|
87
|
+
|
|
88
|
+
def support_concurrency
|
|
89
|
+
# SQLite doesn't support parallel writes
|
|
90
|
+
!(ENV['DB'] =~ /sqlite/)
|
|
91
|
+
end
|
|
92
|
+
|
|
89
93
|
RSpec.configure do |config|
|
|
90
94
|
config.before(:each) do
|
|
91
95
|
DatabaseCleaner.start
|
|
@@ -100,4 +104,7 @@ RSpec.configure do |config|
|
|
|
100
104
|
config.after(:all) do
|
|
101
105
|
FileUtils.remove_entry_secure ENV['FLOCK_DIR']
|
|
102
106
|
end
|
|
107
|
+
config.filter_run_excluding :concurrency => !support_concurrency
|
|
103
108
|
end
|
|
109
|
+
|
|
110
|
+
|
data/spec/uuid_tag_spec.rb
CHANGED
data/tests.sh
ADDED
metadata
CHANGED
|
@@ -1,195 +1,195 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: closure_tree
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 4.
|
|
4
|
+
version: 4.5.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Matthew McEachen
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2014-
|
|
11
|
+
date: 2014-05-18 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: activerecord
|
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
|
16
16
|
requirements:
|
|
17
|
-
- -
|
|
17
|
+
- - ">="
|
|
18
18
|
- !ruby/object:Gem::Version
|
|
19
|
-
version: 3.
|
|
19
|
+
version: 3.2.0
|
|
20
20
|
type: :runtime
|
|
21
21
|
prerelease: false
|
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
|
23
23
|
requirements:
|
|
24
|
-
- -
|
|
24
|
+
- - ">="
|
|
25
25
|
- !ruby/object:Gem::Version
|
|
26
|
-
version: 3.
|
|
26
|
+
version: 3.2.0
|
|
27
27
|
- !ruby/object:Gem::Dependency
|
|
28
28
|
name: with_advisory_lock
|
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
|
30
30
|
requirements:
|
|
31
|
-
- -
|
|
31
|
+
- - ">="
|
|
32
32
|
- !ruby/object:Gem::Version
|
|
33
33
|
version: 0.0.9
|
|
34
34
|
type: :runtime
|
|
35
35
|
prerelease: false
|
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
|
37
37
|
requirements:
|
|
38
|
-
- -
|
|
38
|
+
- - ">="
|
|
39
39
|
- !ruby/object:Gem::Version
|
|
40
40
|
version: 0.0.9
|
|
41
41
|
- !ruby/object:Gem::Dependency
|
|
42
42
|
name: rake
|
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
|
44
44
|
requirements:
|
|
45
|
-
- -
|
|
45
|
+
- - ">="
|
|
46
46
|
- !ruby/object:Gem::Version
|
|
47
47
|
version: '0'
|
|
48
48
|
type: :development
|
|
49
49
|
prerelease: false
|
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
|
51
51
|
requirements:
|
|
52
|
-
- -
|
|
52
|
+
- - ">="
|
|
53
53
|
- !ruby/object:Gem::Version
|
|
54
54
|
version: '0'
|
|
55
55
|
- !ruby/object:Gem::Dependency
|
|
56
56
|
name: yard
|
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
|
58
58
|
requirements:
|
|
59
|
-
- -
|
|
59
|
+
- - ">="
|
|
60
60
|
- !ruby/object:Gem::Version
|
|
61
61
|
version: '0'
|
|
62
62
|
type: :development
|
|
63
63
|
prerelease: false
|
|
64
64
|
version_requirements: !ruby/object:Gem::Requirement
|
|
65
65
|
requirements:
|
|
66
|
-
- -
|
|
66
|
+
- - ">="
|
|
67
67
|
- !ruby/object:Gem::Version
|
|
68
68
|
version: '0'
|
|
69
69
|
- !ruby/object:Gem::Dependency
|
|
70
70
|
name: rspec
|
|
71
71
|
requirement: !ruby/object:Gem::Requirement
|
|
72
72
|
requirements:
|
|
73
|
-
- -
|
|
73
|
+
- - ">="
|
|
74
74
|
- !ruby/object:Gem::Version
|
|
75
75
|
version: '0'
|
|
76
76
|
type: :development
|
|
77
77
|
prerelease: false
|
|
78
78
|
version_requirements: !ruby/object:Gem::Requirement
|
|
79
79
|
requirements:
|
|
80
|
-
- -
|
|
80
|
+
- - ">="
|
|
81
81
|
- !ruby/object:Gem::Version
|
|
82
82
|
version: '0'
|
|
83
83
|
- !ruby/object:Gem::Dependency
|
|
84
84
|
name: rspec-instafail
|
|
85
85
|
requirement: !ruby/object:Gem::Requirement
|
|
86
86
|
requirements:
|
|
87
|
-
- -
|
|
87
|
+
- - ">="
|
|
88
88
|
- !ruby/object:Gem::Version
|
|
89
89
|
version: '0'
|
|
90
90
|
type: :development
|
|
91
91
|
prerelease: false
|
|
92
92
|
version_requirements: !ruby/object:Gem::Requirement
|
|
93
93
|
requirements:
|
|
94
|
-
- -
|
|
94
|
+
- - ">="
|
|
95
95
|
- !ruby/object:Gem::Version
|
|
96
96
|
version: '0'
|
|
97
97
|
- !ruby/object:Gem::Dependency
|
|
98
|
-
name:
|
|
98
|
+
name: rspec-rails
|
|
99
99
|
requirement: !ruby/object:Gem::Requirement
|
|
100
100
|
requirements:
|
|
101
|
-
- -
|
|
101
|
+
- - ">="
|
|
102
102
|
- !ruby/object:Gem::Version
|
|
103
103
|
version: '0'
|
|
104
104
|
type: :development
|
|
105
105
|
prerelease: false
|
|
106
106
|
version_requirements: !ruby/object:Gem::Requirement
|
|
107
107
|
requirements:
|
|
108
|
-
- -
|
|
108
|
+
- - ">="
|
|
109
109
|
- !ruby/object:Gem::Version
|
|
110
110
|
version: '0'
|
|
111
111
|
- !ruby/object:Gem::Dependency
|
|
112
|
-
name:
|
|
112
|
+
name: mysql2
|
|
113
113
|
requirement: !ruby/object:Gem::Requirement
|
|
114
114
|
requirements:
|
|
115
|
-
- -
|
|
115
|
+
- - ">="
|
|
116
116
|
- !ruby/object:Gem::Version
|
|
117
117
|
version: '0'
|
|
118
118
|
type: :development
|
|
119
119
|
prerelease: false
|
|
120
120
|
version_requirements: !ruby/object:Gem::Requirement
|
|
121
121
|
requirements:
|
|
122
|
-
- -
|
|
122
|
+
- - ">="
|
|
123
123
|
- !ruby/object:Gem::Version
|
|
124
124
|
version: '0'
|
|
125
125
|
- !ruby/object:Gem::Dependency
|
|
126
|
-
name:
|
|
126
|
+
name: pg
|
|
127
127
|
requirement: !ruby/object:Gem::Requirement
|
|
128
128
|
requirements:
|
|
129
|
-
- -
|
|
129
|
+
- - ">="
|
|
130
130
|
- !ruby/object:Gem::Version
|
|
131
131
|
version: '0'
|
|
132
132
|
type: :development
|
|
133
133
|
prerelease: false
|
|
134
134
|
version_requirements: !ruby/object:Gem::Requirement
|
|
135
135
|
requirements:
|
|
136
|
-
- -
|
|
136
|
+
- - ">="
|
|
137
137
|
- !ruby/object:Gem::Version
|
|
138
138
|
version: '0'
|
|
139
139
|
- !ruby/object:Gem::Dependency
|
|
140
|
-
name:
|
|
140
|
+
name: sqlite3
|
|
141
141
|
requirement: !ruby/object:Gem::Requirement
|
|
142
142
|
requirements:
|
|
143
|
-
- -
|
|
143
|
+
- - ">="
|
|
144
144
|
- !ruby/object:Gem::Version
|
|
145
145
|
version: '0'
|
|
146
146
|
type: :development
|
|
147
147
|
prerelease: false
|
|
148
148
|
version_requirements: !ruby/object:Gem::Requirement
|
|
149
149
|
requirements:
|
|
150
|
-
- -
|
|
150
|
+
- - ">="
|
|
151
151
|
- !ruby/object:Gem::Version
|
|
152
152
|
version: '0'
|
|
153
153
|
- !ruby/object:Gem::Dependency
|
|
154
|
-
name:
|
|
154
|
+
name: uuidtools
|
|
155
155
|
requirement: !ruby/object:Gem::Requirement
|
|
156
156
|
requirements:
|
|
157
|
-
- -
|
|
157
|
+
- - ">="
|
|
158
158
|
- !ruby/object:Gem::Version
|
|
159
159
|
version: '0'
|
|
160
160
|
type: :development
|
|
161
161
|
prerelease: false
|
|
162
162
|
version_requirements: !ruby/object:Gem::Requirement
|
|
163
163
|
requirements:
|
|
164
|
-
- -
|
|
164
|
+
- - ">="
|
|
165
165
|
- !ruby/object:Gem::Version
|
|
166
166
|
version: '0'
|
|
167
167
|
- !ruby/object:Gem::Dependency
|
|
168
|
-
name:
|
|
168
|
+
name: database_cleaner
|
|
169
169
|
requirement: !ruby/object:Gem::Requirement
|
|
170
170
|
requirements:
|
|
171
|
-
- -
|
|
171
|
+
- - ">="
|
|
172
172
|
- !ruby/object:Gem::Version
|
|
173
173
|
version: '0'
|
|
174
174
|
type: :development
|
|
175
175
|
prerelease: false
|
|
176
176
|
version_requirements: !ruby/object:Gem::Requirement
|
|
177
177
|
requirements:
|
|
178
|
-
- -
|
|
178
|
+
- - ">="
|
|
179
179
|
- !ruby/object:Gem::Version
|
|
180
180
|
version: '0'
|
|
181
181
|
- !ruby/object:Gem::Dependency
|
|
182
|
-
name:
|
|
182
|
+
name: appraisal
|
|
183
183
|
requirement: !ruby/object:Gem::Requirement
|
|
184
184
|
requirements:
|
|
185
|
-
- -
|
|
185
|
+
- - ">="
|
|
186
186
|
- !ruby/object:Gem::Version
|
|
187
187
|
version: '0'
|
|
188
188
|
type: :development
|
|
189
189
|
prerelease: false
|
|
190
190
|
version_requirements: !ruby/object:Gem::Requirement
|
|
191
191
|
requirements:
|
|
192
|
-
- -
|
|
192
|
+
- - ">="
|
|
193
193
|
- !ruby/object:Gem::Version
|
|
194
194
|
version: '0'
|
|
195
195
|
description: Easily and efficiently make your ActiveRecord model support hierarchies
|
|
@@ -199,9 +199,22 @@ executables: []
|
|
|
199
199
|
extensions: []
|
|
200
200
|
extra_rdoc_files: []
|
|
201
201
|
files:
|
|
202
|
+
- ".gitignore"
|
|
203
|
+
- ".travis.yml"
|
|
204
|
+
- ".yardopts"
|
|
205
|
+
- Appraisals
|
|
206
|
+
- CHANGELOG.md
|
|
207
|
+
- Gemfile
|
|
202
208
|
- MIT-LICENSE
|
|
203
209
|
- README.md
|
|
204
210
|
- Rakefile
|
|
211
|
+
- closure_tree.gemspec
|
|
212
|
+
- gemfiles/activerecord_3.2.gemfile
|
|
213
|
+
- gemfiles/activerecord_4.0.gemfile
|
|
214
|
+
- gemfiles/activerecord_4.1.gemfile
|
|
215
|
+
- gemfiles/activerecord_edge.gemfile
|
|
216
|
+
- img/example.png
|
|
217
|
+
- img/preorder.png
|
|
205
218
|
- lib/closure_tree.rb
|
|
206
219
|
- lib/closure_tree/acts_as_tree.rb
|
|
207
220
|
- lib/closure_tree/deterministic_ordering.rb
|
|
@@ -216,12 +229,15 @@ files:
|
|
|
216
229
|
- lib/closure_tree/support_attributes.rb
|
|
217
230
|
- lib/closure_tree/support_flags.rb
|
|
218
231
|
- lib/closure_tree/version.rb
|
|
232
|
+
- mktree.rb
|
|
219
233
|
- spec/cuisine_type_spec.rb
|
|
220
234
|
- spec/db/database.yml
|
|
221
235
|
- spec/db/schema.rb
|
|
222
236
|
- spec/fixtures/tags.yml
|
|
237
|
+
- spec/hierarchy_maintenance_spec.rb
|
|
223
238
|
- spec/label_spec.rb
|
|
224
239
|
- spec/metal_spec.rb
|
|
240
|
+
- spec/model_spec.rb
|
|
225
241
|
- spec/namespace_type_spec.rb
|
|
226
242
|
- spec/parallel_prepend_sibling_spec.rb
|
|
227
243
|
- spec/parallel_spec.rb
|
|
@@ -232,6 +248,7 @@ files:
|
|
|
232
248
|
- spec/tag_spec.rb
|
|
233
249
|
- spec/user_spec.rb
|
|
234
250
|
- spec/uuid_tag_spec.rb
|
|
251
|
+
- tests.sh
|
|
235
252
|
homepage: http://mceachen.github.io/closure_tree/
|
|
236
253
|
licenses:
|
|
237
254
|
- MIT
|
|
@@ -242,17 +259,17 @@ require_paths:
|
|
|
242
259
|
- lib
|
|
243
260
|
required_ruby_version: !ruby/object:Gem::Requirement
|
|
244
261
|
requirements:
|
|
245
|
-
- -
|
|
262
|
+
- - ">="
|
|
246
263
|
- !ruby/object:Gem::Version
|
|
247
264
|
version: '0'
|
|
248
265
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
249
266
|
requirements:
|
|
250
|
-
- -
|
|
267
|
+
- - ">="
|
|
251
268
|
- !ruby/object:Gem::Version
|
|
252
269
|
version: '0'
|
|
253
270
|
requirements: []
|
|
254
271
|
rubyforge_project:
|
|
255
|
-
rubygems_version: 2.2.
|
|
272
|
+
rubygems_version: 2.2.2
|
|
256
273
|
signing_key:
|
|
257
274
|
specification_version: 4
|
|
258
275
|
summary: Easily and efficiently make your ActiveRecord model support hierarchies
|
|
@@ -261,8 +278,10 @@ test_files:
|
|
|
261
278
|
- spec/db/database.yml
|
|
262
279
|
- spec/db/schema.rb
|
|
263
280
|
- spec/fixtures/tags.yml
|
|
281
|
+
- spec/hierarchy_maintenance_spec.rb
|
|
264
282
|
- spec/label_spec.rb
|
|
265
283
|
- spec/metal_spec.rb
|
|
284
|
+
- spec/model_spec.rb
|
|
266
285
|
- spec/namespace_type_spec.rb
|
|
267
286
|
- spec/parallel_prepend_sibling_spec.rb
|
|
268
287
|
- spec/parallel_spec.rb
|