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