ancestry 2.1.0 → 2.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -13
- data/MIT-LICENSE +1 -1
- data/README.rdoc +71 -19
- data/ancestry.gemspec +20 -11
- data/lib/ancestry/class_methods.rb +22 -13
- data/lib/ancestry/has_ancestry.rb +5 -4
- data/lib/ancestry/instance_methods.rb +40 -13
- metadata +76 -20
checksums.yaml
CHANGED
@@ -1,15 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
|
5
|
-
data.tar.gz: !binary |-
|
6
|
-
ZWRkMWYxOWZhOTJiNjU2MTE2ZTcyYWIwM2FlNmVmNjk0NjBkZGE2ZQ==
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 1b34c7c664ec5c1a9ac92379c65d9ea196658a3e
|
4
|
+
data.tar.gz: 2d9ff6493829ef26b6b8f3591404f7567139c717
|
7
5
|
SHA512:
|
8
|
-
metadata.gz:
|
9
|
-
|
10
|
-
OTg2MzVjY2Q3MWEyNTEzZDUzNjc4OTA5NWVhNTFiNWJjYjFiMTQxNjhkYzM5
|
11
|
-
ODNlY2Y0MmIwZDc2ODQ4YTRiNmYxMWMwOTJiNzE0NDZmMDlhZGQ=
|
12
|
-
data.tar.gz: !binary |-
|
13
|
-
N2E1ZjAwY2M1YjkzZTBlNWRkNDQ0ZTVlMDM3OTg3YmE0ZDgwMzNlNTdjOTFh
|
14
|
-
Y2NkYWY0NGUwNDFjZWI3OTZkMTAwMTBmNDI4OWZlOGQyMDRiZmQxOTgyOWFi
|
15
|
-
ZGFmYzk1YTExNjFhYTczNzIxMGE2NGVlZTA4ZGMwYWViMjU3NGE=
|
6
|
+
metadata.gz: d4b6408a4e4582b8cb654e4d38560f1f7b0b743b55023ff6668449a75847874036975faf53c74c18e75fbc59c6eb6d8d1c3bd7d22b28ce97595bcd5d56bd1f49
|
7
|
+
data.tar.gz: b06389bb0d03045bd0f9f82ab2dac3db63c8ca2996c87bcc4f46bb9b71d876090bc136b928cd5ac9d2c3c6b62ed48cd0ca2175e5c5e9a0f6c2e169a6ef24e005
|
data/MIT-LICENSE
CHANGED
data/README.rdoc
CHANGED
@@ -1,5 +1,7 @@
|
|
1
|
-
{<img src="https://travis-ci.org/stefankroes/ancestry.
|
2
|
-
{<img src="https://coveralls.io/repos/stefankroes/ancestry/badge.
|
1
|
+
{<img src="https://travis-ci.org/stefankroes/ancestry.svg?branch=master" alt="Build Status" />}[https://travis-ci.org/stefankroes/ancestry]
|
2
|
+
{<img src="https://coveralls.io/repos/stefankroes/ancestry/badge.svg" alt="Coverage Status" />}[https://coveralls.io/r/stefankroes/ancestry]
|
3
|
+
{<img src="https://badges.gitter.im/Join Chat.svg" alt="Gitter" />}[https://gitter.im/stefankroes/ancestry?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge]
|
4
|
+
{<img src="https://hakiri.io/github/stefankroes/ancestry/master.svg" alt="Security" />}[https://hakiri.io/github/stefankroes/ancestry/master]
|
3
5
|
|
4
6
|
= Ancestry
|
5
7
|
|
@@ -9,20 +11,51 @@ Ancestry is a gem/plugin that allows the records of a Ruby on Rails ActiveRecord
|
|
9
11
|
|
10
12
|
To apply Ancestry to any ActiveRecord model, follow these simple steps:
|
11
13
|
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
14
|
+
== Install
|
15
|
+
=== Rails 2
|
16
|
+
- See 1-3-stable branch
|
17
|
+
=== Rails 3 and 4
|
18
|
+
- Add to Gemfile:
|
19
|
+
# Gemfile
|
20
|
+
|
21
|
+
gem 'ancestry'
|
22
|
+
- Install required gems:
|
23
|
+
$ bundle install
|
24
|
+
|
25
|
+
== Add ancestry column to your table
|
26
|
+
- Create migration:
|
27
|
+
$ rails g migration add_ancestry_to_[table] ancestry:string
|
28
|
+
- Add index to migration:
|
29
|
+
# db/migrate/[date]_add_ancestry_to_[table].rb
|
30
|
+
|
31
|
+
class AddAncestryTo[Table] < ActiveRecord::Migration
|
32
|
+
# Rails 4 Syntax
|
33
|
+
def change
|
34
|
+
add_column [table], :ancestry, :string
|
35
|
+
add_index [table], :ancestry
|
36
|
+
end
|
37
|
+
|
38
|
+
# Rails 3 Syntax
|
39
|
+
def up
|
40
|
+
add_column [table], :ancestry, :string
|
41
|
+
add_index [table], :ancestry
|
42
|
+
end
|
43
|
+
|
44
|
+
def down
|
45
|
+
remove_column [table], :ancestry
|
46
|
+
remove_index [table], :ancestry
|
47
|
+
end
|
48
|
+
|
49
|
+
- Migrate your database:
|
50
|
+
$ rake db:migrate
|
51
|
+
|
52
|
+
== Add ancestry to your model
|
53
|
+
- Add to app/models/[model].rb:
|
54
|
+
# app/models/[model.rb]
|
55
|
+
|
56
|
+
class [Model] < ActiveRecord::Base
|
57
|
+
has_ancestry
|
58
|
+
end
|
26
59
|
|
27
60
|
Your model is now a tree!
|
28
61
|
|
@@ -57,7 +90,7 @@ To navigate an Ancestry model, use the following methods on any instance / recor
|
|
57
90
|
child_ids Returns a list of child ids
|
58
91
|
has_children? Returns true if the record has any children, false otherwise
|
59
92
|
is_childless? Returns true is the record has no children, false otherwise
|
60
|
-
siblings Scopes the model on siblings of the record, the record itself is included
|
93
|
+
siblings Scopes the model on siblings of the record, the record itself is included*
|
61
94
|
sibling_ids Returns a list of sibling ids
|
62
95
|
has_siblings? Returns true if the record's parent has more than one child
|
63
96
|
is_only_child? Returns true if the record is the only child of its parent
|
@@ -67,6 +100,8 @@ To navigate an Ancestry model, use the following methods on any instance / recor
|
|
67
100
|
subtree_ids Returns a list of all ids in the record's subtree
|
68
101
|
depth Return the depth of the node, root nodes are at depth 0
|
69
102
|
|
103
|
+
* If the record is a root, other root records are considered siblings
|
104
|
+
|
70
105
|
= Options for has_ancestry
|
71
106
|
|
72
107
|
The has_ancestry methods supports the following options:
|
@@ -174,6 +209,23 @@ To get the arranged nodes as a nested array of hashes for serialization:
|
|
174
209
|
}
|
175
210
|
]
|
176
211
|
|
212
|
+
You can also supply your own serialization logic using blocks:
|
213
|
+
|
214
|
+
For example, using Active Model Serializers:
|
215
|
+
|
216
|
+
TreeNode.arrange_serializable do |parent, children|
|
217
|
+
MySerializer.new(parent, children: children)
|
218
|
+
end
|
219
|
+
|
220
|
+
Or plain hashes:
|
221
|
+
|
222
|
+
TreeNode.arrange_serializable do |parent, children|
|
223
|
+
{
|
224
|
+
my_id: parent.id
|
225
|
+
my_children: children
|
226
|
+
}
|
227
|
+
end
|
228
|
+
|
177
229
|
The result of arrange_serializable can easily be serialized to json with 'to_json', or some other format:
|
178
230
|
|
179
231
|
TreeNode.arrange_serializable.to_json
|
@@ -269,10 +321,10 @@ In the example above, the ancestry column is created as a string. This puts a li
|
|
269
321
|
|
270
322
|
The materialised path pattern requires Ancestry to use a 'like' condition in order to fetch descendants. This should not be particularly slow however since the the condition never starts with a wildcard which allows the DBMS to use the column index. If you have any data on performance with a large number of records, please drop me line.
|
271
323
|
|
272
|
-
= Contributing and
|
324
|
+
= Contributing and license
|
273
325
|
|
274
326
|
I will try to keep Ancestry up to date with changing versions of Rails and Ruby and also with any bug reports I might receive. I will implement new features on request as I see fit and have time.
|
275
327
|
|
276
328
|
Question? Bug report? Faulty/incomplete documentation? Feature request? Please post an issue on 'http://github.com/stefankroes/ancestry/issues'. Make sure you have read the documentation and you have included tests and documentation with any pull request.
|
277
329
|
|
278
|
-
Copyright (c)
|
330
|
+
Copyright (c) 2016 Stefan Kroes, released under the MIT license
|
data/ancestry.gemspec
CHANGED
@@ -1,3 +1,7 @@
|
|
1
|
+
lib = File.expand_path('../lib/', __FILE__)
|
2
|
+
$:.unshift lib unless $:.include?(lib)
|
3
|
+
require 'ancestry/version'
|
4
|
+
|
1
5
|
Gem::Specification.new do |s|
|
2
6
|
s.name = 'ancestry'
|
3
7
|
s.summary = 'Organize ActiveRecord model into a tree structure'
|
@@ -11,7 +15,7 @@ Gem::Specification.new do |s|
|
|
11
15
|
orphaned records.
|
12
16
|
EOF
|
13
17
|
|
14
|
-
s.version =
|
18
|
+
s.version = Ancestry::VERSION
|
15
19
|
|
16
20
|
s.author = 'Stefan Kroes'
|
17
21
|
s.email = 's.a.kroes@gmail.com'
|
@@ -19,17 +23,22 @@ EOF
|
|
19
23
|
s.license = 'MIT'
|
20
24
|
|
21
25
|
s.files = [
|
22
|
-
'ancestry.gemspec',
|
23
|
-
'init.rb',
|
24
|
-
'install.rb',
|
25
|
-
'lib/ancestry.rb',
|
26
|
-
'lib/ancestry/has_ancestry.rb',
|
27
|
-
'lib/ancestry/exceptions.rb',
|
28
|
-
'lib/ancestry/class_methods.rb',
|
29
|
-
'lib/ancestry/instance_methods.rb',
|
30
|
-
'MIT-LICENSE',
|
26
|
+
'ancestry.gemspec',
|
27
|
+
'init.rb',
|
28
|
+
'install.rb',
|
29
|
+
'lib/ancestry.rb',
|
30
|
+
'lib/ancestry/has_ancestry.rb',
|
31
|
+
'lib/ancestry/exceptions.rb',
|
32
|
+
'lib/ancestry/class_methods.rb',
|
33
|
+
'lib/ancestry/instance_methods.rb',
|
34
|
+
'MIT-LICENSE',
|
31
35
|
'README.rdoc'
|
32
36
|
]
|
33
37
|
|
34
|
-
s.
|
38
|
+
s.required_ruby_version = '>= 1.8.7'
|
39
|
+
s.add_runtime_dependency 'activerecord', '>= 3.0.0'
|
40
|
+
s.add_development_dependency 'rake', '~> 10.0'
|
41
|
+
s.add_development_dependency 'test-unit'
|
42
|
+
s.add_development_dependency 'minitest'
|
43
|
+
s.add_development_dependency 'sqlite3'
|
35
44
|
end
|
@@ -42,25 +42,34 @@ module Ancestry
|
|
42
42
|
# Arrange array of nodes into a nested hash of the form
|
43
43
|
# {node => children}, where children = {} if the node has no children
|
44
44
|
def arrange_nodes(nodes)
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
45
|
+
arranged = ActiveSupport::OrderedHash.new
|
46
|
+
min_depth = Float::INFINITY
|
47
|
+
index = Hash.new { |h, k| h[k] = ActiveSupport::OrderedHash.new }
|
48
|
+
|
49
|
+
nodes.each do |node|
|
50
|
+
children = index[node.id]
|
51
|
+
index[node.parent_id][node] = children
|
52
|
+
|
53
|
+
depth = node.depth
|
54
|
+
if depth < min_depth
|
55
|
+
min_depth = depth
|
56
|
+
arranged.clear
|
57
|
+
end
|
58
|
+
arranged[node] = children if depth == min_depth
|
56
59
|
end
|
60
|
+
|
61
|
+
arranged
|
57
62
|
end
|
58
63
|
|
59
64
|
# Arrangement to nested array
|
60
|
-
def arrange_serializable options={}, nodes=nil
|
65
|
+
def arrange_serializable options={}, nodes=nil, &block
|
61
66
|
nodes = arrange(options) if nodes.nil?
|
62
67
|
nodes.map do |parent, children|
|
63
|
-
|
68
|
+
if block_given?
|
69
|
+
yield parent, arrange_serializable(options, children, &block)
|
70
|
+
else
|
71
|
+
parent.serializable_hash.merge 'children' => arrange_serializable(options, children)
|
72
|
+
end
|
64
73
|
end
|
65
74
|
end
|
66
75
|
|
@@ -43,8 +43,9 @@ class << ActiveRecord::Base
|
|
43
43
|
scope :descendants_of, lambda { |object| where(to_node(object).descendant_conditions) }
|
44
44
|
scope :subtree_of, lambda { |object| where(to_node(object).subtree_conditions) }
|
45
45
|
scope :siblings_of, lambda { |object| where(to_node(object).sibling_conditions) }
|
46
|
-
scope :ordered_by_ancestry, lambda { reorder("(
|
47
|
-
scope :ordered_by_ancestry_and, lambda { |order| reorder("(
|
46
|
+
scope :ordered_by_ancestry, lambda { reorder("(CASE WHEN #{connection.quote_table_name(table_name)}.#{connection.quote_column_name(ancestry_column)} IS NULL THEN 0 ELSE 1 END), #{connection.quote_table_name(table_name)}.#{connection.quote_column_name(ancestry_column)}") }
|
47
|
+
scope :ordered_by_ancestry_and, lambda { |order| reorder("(CASE WHEN #{connection.quote_table_name(table_name)}.#{connection.quote_column_name(ancestry_column)} IS NULL THEN 0 ELSE 1 END), #{connection.quote_table_name(table_name)}.#{connection.quote_column_name(ancestry_column)}, #{order}") }
|
48
|
+
scope :path_of, lambda { |object| to_node(object).path }
|
48
49
|
|
49
50
|
# Update descendants with new ancestry before save
|
50
51
|
before_save :update_descendants_with_new_ancestry
|
@@ -74,9 +75,9 @@ class << ActiveRecord::Base
|
|
74
75
|
}
|
75
76
|
end
|
76
77
|
|
77
|
-
after_save :touch_ancestors_callback
|
78
78
|
after_touch :touch_ancestors_callback
|
79
79
|
after_destroy :touch_ancestors_callback
|
80
|
+
after_save :touch_ancestors_callback, if: :changed?
|
80
81
|
end
|
81
82
|
end
|
82
83
|
|
@@ -86,4 +87,4 @@ ActiveSupport.on_load :active_record do
|
|
86
87
|
alias_method :acts_as_tree, :has_ancestry
|
87
88
|
end
|
88
89
|
end
|
89
|
-
end
|
90
|
+
end
|
@@ -53,6 +53,8 @@ module Ancestry
|
|
53
53
|
descendants.each do |descendant|
|
54
54
|
descendant.without_ancestry_callbacks do
|
55
55
|
new_ancestry = descendant.ancestor_ids.delete_if { |x| x == self.id }.join("/")
|
56
|
+
# check for empty string if it's then set to nil
|
57
|
+
new_ancestry = nil if new_ancestry.empty?
|
56
58
|
descendant.update_attribute descendant.class.ancestry_column, new_ancestry || nil
|
57
59
|
end
|
58
60
|
end
|
@@ -92,7 +94,7 @@ module Ancestry
|
|
92
94
|
end
|
93
95
|
|
94
96
|
# Ancestors
|
95
|
-
|
97
|
+
|
96
98
|
def ancestry_changed?
|
97
99
|
changed.include?(self.ancestry_base_class.ancestry_column.to_s)
|
98
100
|
end
|
@@ -143,8 +145,12 @@ module Ancestry
|
|
143
145
|
write_attribute self.ancestry_base_class.depth_cache_column, depth
|
144
146
|
end
|
145
147
|
|
148
|
+
def ancestor_of?(node)
|
149
|
+
node.ancestor_ids.include?(self.id)
|
150
|
+
end
|
151
|
+
|
146
152
|
# Parent
|
147
|
-
|
153
|
+
|
148
154
|
def parent= parent
|
149
155
|
write_attribute(self.ancestry_base_class.ancestry_column, if parent.nil? then nil else parent.child_ancestry end)
|
150
156
|
end
|
@@ -165,8 +171,12 @@ module Ancestry
|
|
165
171
|
parent_id.present?
|
166
172
|
end
|
167
173
|
|
174
|
+
def parent_of?(node)
|
175
|
+
self.id == node.parent_id
|
176
|
+
end
|
177
|
+
|
168
178
|
# Root
|
169
|
-
|
179
|
+
|
170
180
|
def root_id
|
171
181
|
if ancestor_ids.empty? then id else ancestor_ids.first end
|
172
182
|
end
|
@@ -180,8 +190,12 @@ module Ancestry
|
|
180
190
|
end
|
181
191
|
alias :root? :is_root?
|
182
192
|
|
193
|
+
def root_of?(node)
|
194
|
+
self.id == node.root_id
|
195
|
+
end
|
196
|
+
|
183
197
|
# Children
|
184
|
-
|
198
|
+
|
185
199
|
def child_conditions
|
186
200
|
t = get_arel_table
|
187
201
|
t[get_ancestry_column].eq(child_ancestry)
|
@@ -205,8 +219,12 @@ module Ancestry
|
|
205
219
|
end
|
206
220
|
alias_method :childless?, :is_childless?
|
207
221
|
|
222
|
+
def child_of?(node)
|
223
|
+
self.parent_id == node.id
|
224
|
+
end
|
225
|
+
|
208
226
|
# Siblings
|
209
|
-
|
227
|
+
|
210
228
|
def sibling_conditions
|
211
229
|
t = get_arel_table
|
212
230
|
t[get_ancestry_column].eq(read_attribute(self.ancestry_base_class.ancestry_column))
|
@@ -230,8 +248,12 @@ module Ancestry
|
|
230
248
|
end
|
231
249
|
alias_method :only_child?, :is_only_child?
|
232
250
|
|
251
|
+
def sibling_of?(node)
|
252
|
+
self.ancestry == node.ancestry
|
253
|
+
end
|
254
|
+
|
233
255
|
# Descendants
|
234
|
-
|
256
|
+
|
235
257
|
def descendant_conditions
|
236
258
|
t = get_arel_table
|
237
259
|
t[get_ancestry_column].matches("#{child_ancestry}/%").or(t[get_ancestry_column].eq(child_ancestry))
|
@@ -245,11 +267,15 @@ module Ancestry
|
|
245
267
|
descendants(depth_options).select(self.ancestry_base_class.primary_key).collect(&self.ancestry_base_class.primary_key.to_sym)
|
246
268
|
end
|
247
269
|
|
270
|
+
def descendant_of?(node)
|
271
|
+
ancestor_ids.include?(node.id)
|
272
|
+
end
|
273
|
+
|
248
274
|
# Subtree
|
249
|
-
|
275
|
+
|
250
276
|
def subtree_conditions
|
251
277
|
t = get_arel_table
|
252
|
-
t[get_primary_key_column].eq(self.id)
|
278
|
+
descendant_conditions.or(t[get_primary_key_column].eq(self.id))
|
253
279
|
end
|
254
280
|
|
255
281
|
def subtree depth_options = {}
|
@@ -261,7 +287,7 @@ module Ancestry
|
|
261
287
|
end
|
262
288
|
|
263
289
|
# Callback disabling
|
264
|
-
|
290
|
+
|
265
291
|
def without_ancestry_callbacks
|
266
292
|
@disable_ancestry_callbacks = true
|
267
293
|
yield
|
@@ -269,13 +295,13 @@ module Ancestry
|
|
269
295
|
end
|
270
296
|
|
271
297
|
def ancestry_callbacks_disabled?
|
272
|
-
|
298
|
+
defined?(@disable_ancestry_callbacks) && @disable_ancestry_callbacks
|
273
299
|
end
|
274
300
|
|
275
301
|
private
|
276
302
|
|
277
303
|
def cast_primary_key(key)
|
278
|
-
if [:string, :uuid].include? primary_key_type
|
304
|
+
if [:string, :uuid, :text].include? primary_key_type
|
279
305
|
key
|
280
306
|
else
|
281
307
|
key.to_i
|
@@ -292,9 +318,10 @@ module Ancestry
|
|
292
318
|
end
|
293
319
|
end
|
294
320
|
|
295
|
-
# Validates the ancestry, but can also be applied if validation is bypassed to determine if
|
321
|
+
# Validates the ancestry, but can also be applied if validation is bypassed to determine if children should be affected
|
296
322
|
def sane_ancestry?
|
297
|
-
|
323
|
+
ancestry_value = read_attribute(self.ancestry_base_class.ancestry_column)
|
324
|
+
ancestry_value.nil? || (ancestry_value.to_s =~ Ancestry::ANCESTRY_PATTERN && !ancestor_ids.include?(self.id))
|
298
325
|
end
|
299
326
|
|
300
327
|
def unscoped_find id
|
metadata
CHANGED
@@ -1,51 +1,108 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ancestry
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.
|
4
|
+
version: 2.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Stefan Kroes
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2016-10-25 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
19
|
version: 3.0.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
26
|
version: 3.0.0
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '10.0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '10.0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: test-unit
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: minitest
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: sqlite3
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
83
|
+
description: |2
|
84
|
+
Ancestry allows the records of a ActiveRecord model to be organized in a tree
|
85
|
+
structure, using a single, intuitively formatted database column. It exposes
|
86
|
+
all the standard tree structure relations (ancestors, parent, root, children,
|
87
|
+
siblings, descendants) and all of them can be fetched in a single sql query.
|
88
|
+
Additional features are named_scopes, integrity checking, integrity restoration,
|
89
|
+
arrangement of (sub)tree into hashes and different strategies for dealing with
|
90
|
+
orphaned records.
|
34
91
|
email: s.a.kroes@gmail.com
|
35
92
|
executables: []
|
36
93
|
extensions: []
|
37
94
|
extra_rdoc_files: []
|
38
95
|
files:
|
96
|
+
- MIT-LICENSE
|
97
|
+
- README.rdoc
|
39
98
|
- ancestry.gemspec
|
40
99
|
- init.rb
|
41
100
|
- install.rb
|
42
101
|
- lib/ancestry.rb
|
43
|
-
- lib/ancestry/has_ancestry.rb
|
44
|
-
- lib/ancestry/exceptions.rb
|
45
102
|
- lib/ancestry/class_methods.rb
|
103
|
+
- lib/ancestry/exceptions.rb
|
104
|
+
- lib/ancestry/has_ancestry.rb
|
46
105
|
- lib/ancestry/instance_methods.rb
|
47
|
-
- MIT-LICENSE
|
48
|
-
- README.rdoc
|
49
106
|
homepage: http://github.com/stefankroes/ancestry
|
50
107
|
licenses:
|
51
108
|
- MIT
|
@@ -56,19 +113,18 @@ require_paths:
|
|
56
113
|
- lib
|
57
114
|
required_ruby_version: !ruby/object:Gem::Requirement
|
58
115
|
requirements:
|
59
|
-
- -
|
116
|
+
- - ">="
|
60
117
|
- !ruby/object:Gem::Version
|
61
|
-
version:
|
118
|
+
version: 1.8.7
|
62
119
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
63
120
|
requirements:
|
64
|
-
- -
|
121
|
+
- - ">="
|
65
122
|
- !ruby/object:Gem::Version
|
66
123
|
version: '0'
|
67
124
|
requirements: []
|
68
125
|
rubyforge_project:
|
69
|
-
rubygems_version: 2.1
|
126
|
+
rubygems_version: 2.5.1
|
70
127
|
signing_key:
|
71
128
|
specification_version: 4
|
72
129
|
summary: Organize ActiveRecord model into a tree structure
|
73
130
|
test_files: []
|
74
|
-
has_rdoc:
|