closure_tree 7.0.0 → 7.1.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: aad24f6acfed9da72a06c877919ef7a349680abb951a185307590b42484582e0
4
- data.tar.gz: 543f9482cd9497d99174358b6d342caa6c860608acc51f5989e5d780c1747f58
3
+ metadata.gz: 417c1d78863c2c69db6e25b1fcf4e241c12287adf8db72953652072d36ee7f79
4
+ data.tar.gz: 45505a5b14cd3d9de2e0a823ef4805d27e9b27bc55fe3edbe1ae0aee05d62db1
5
5
  SHA512:
6
- metadata.gz: 69c034fe0ee0278b143758381412ca43663da441bd35a81b67d516d58defc5f19b79d83a28a9fea18984cb105b757b7028c9898cab34eaae98fccb56e7b0d71e
7
- data.tar.gz: 53346203044b6eb82b784bc715105b6a2a5029d8ab8c48665d1bb02bf667bff643ba0768c6dfa6ec476b03b7f5567e28846c8b6b2c7b17344f2d17227ca1e24c
6
+ metadata.gz: c606867a720cc4dd7ddfc608ef0f61e5e06decd8623caa86938629d6089b7b86e3c95f68df864ba306f533d5287e6765559f023e18cc6157410852164fd1f4e0
7
+ data.tar.gz: 0bbd08988841abd22f52d706501d3556ea7cc52319ac212ea86ee1b82315aa83de2cb58327ac21cecaa465a53e9305d73fa0b0ab6031ad58f3e7d04acab4c5d3
data/.gitignore CHANGED
@@ -13,3 +13,4 @@ tmp/
13
13
  *.lock
14
14
  tmp/
15
15
  .ruby-*
16
+ *.iml
@@ -2,13 +2,11 @@ cache: bundler
2
2
  sudo: false
3
3
  language: ruby
4
4
  rvm:
5
- - 2.6.0
6
- - 2.5.1
7
- - 2.4.4
8
- - 2.3.6
9
- - 2.2.10
5
+ - 2.6.3
6
+ - 2.5.5
10
7
 
11
8
  gemfile:
9
+ - gemfiles/activerecord_6.0.gemfile
12
10
  - gemfiles/activerecord_5.2.gemfile
13
11
  - gemfiles/activerecord_5.1.gemfile
14
12
  - gemfiles/activerecord_5.0.gemfile
@@ -20,11 +18,16 @@ env:
20
18
  - DB=mysql
21
19
  - DB=postgresql
22
20
 
21
+ services:
22
+ - mysql
23
+ - postgresql
24
+
23
25
  script: WITH_ADVISORY_LOCK_PREFIX=$TRAVIS_JOB_ID bundle exec rake --trace spec:all
24
26
 
25
27
  matrix:
26
28
  allow_failures:
27
- - gemfile: gemfiles/activerecord_edge.gemfile
28
- - rvm: jruby-head
29
- - rvm: rbx
30
- - rvm: 2.6.0
29
+ - gemfile: gemfiles/activerecord_edge.gemfile
30
+ - gemfile: gemfiles/activerecord_6.0.gemfile
31
+ exclude:
32
+ - rvm: 2.5.5
33
+ gemfile: gemfiles/activerecord_edge.gemfile
data/Appraisals CHANGED
@@ -4,7 +4,7 @@ appraise 'activerecord-4.2' do
4
4
  platforms :ruby do
5
5
  gem 'mysql2', "< 0.5"
6
6
  gem 'pg', "~> 0.21"
7
- gem 'sqlite3'
7
+ gem 'sqlite3', '~> 1.3.13'
8
8
  end
9
9
 
10
10
  platforms :jruby do
@@ -19,7 +19,7 @@ appraise 'activerecord-5.0' do
19
19
  platforms :ruby do
20
20
  gem 'mysql2'
21
21
  gem 'pg'
22
- gem 'sqlite3'
22
+ gem 'sqlite3', '~> 1.3.13'
23
23
  end
24
24
 
25
25
  platforms :jruby do
@@ -34,7 +34,7 @@ appraise 'activerecord-5.1' do
34
34
  platforms :ruby do
35
35
  gem 'mysql2'
36
36
  gem 'pg'
37
- gem 'sqlite3'
37
+ gem 'sqlite3', '~> 1.3.13'
38
38
  end
39
39
 
40
40
  platforms :jruby do
@@ -59,6 +59,21 @@ appraise 'activerecord-5.2' do
59
59
  end
60
60
  end
61
61
 
62
+ appraise 'activerecord-6.0' do
63
+ gem 'activerecord', '~> 6.0.0'
64
+ platforms :ruby do
65
+ gem 'mysql2'
66
+ gem 'pg'
67
+ gem 'sqlite3'
68
+ end
69
+
70
+ platforms :jruby do
71
+ gem 'activerecord-jdbcmysql-adapter'
72
+ gem 'activerecord-jdbcpostgresql-adapter'
73
+ gem 'activerecord-jdbcsqlite3-adapter'
74
+ end
75
+ end
76
+
62
77
  appraise 'activerecord-edge' do
63
78
  gem 'activerecord', github: 'rails/rails'
64
79
  platforms :ruby do
@@ -1,5 +1,10 @@
1
1
  # Changelog
2
2
 
3
+ ### 7.1.0
4
+ Closure Tree is now tested against Rails 6.0
5
+ - Directly require core_ext for String#strip_heredoc[PR 350](https://github.com/ClosureTree/closure_tree/pull/350)
6
+ - Call Module#module_parent instead of deprecated #parent[PR 354](https://github.com/ClosureTree/closure_tree/pull/354)
7
+
3
8
  ### 7.0.0
4
9
  Closure Tree is now tested against Rails 5.2
5
10
 
data/README.md CHANGED
@@ -1,7 +1,5 @@
1
1
  # Closure Tree
2
2
 
3
- __Important: please [vote on the future of ClosureTree](https://github.com/ClosureTree/closure_tree/issues/277)!__
4
-
5
3
  ### Closure_tree lets your ActiveRecord models act as nodes in a [tree data structure](http://en.wikipedia.org/wiki/Tree_%28data_structure%29)
6
4
 
7
5
  Common applications include modeling hierarchical data, like tags, threaded comments, page graphs in CMSes,
@@ -10,7 +8,6 @@ and tracking user referrals.
10
8
  [![Join the chat at https://gitter.im/closure_tree/Lobby](https://badges.gitter.im/closure_tree/Lobby.svg)](https://gitter.im/closure_tree/Lobby?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
11
9
  [![Build Status](https://api.travis-ci.org/ClosureTree/closure_tree.svg?branch=master)](http://travis-ci.org/ClosureTree/closure_tree)
12
10
  [![Gem Version](https://badge.fury.io/rb/closure_tree.svg)](https://badge.fury.io/rb/closure_tree)
13
- [![Dependency Status](https://gemnasium.com/badges/github.com/ClosureTree/closure_tree.svg)](https://gemnasium.com/github.com/ClosureTree/closure_tree)
14
11
 
15
12
  Dramatically more performant than
16
13
  [ancestry](https://github.com/stefankroes/ancestry) and
@@ -28,7 +25,7 @@ closure_tree has some great features:
28
25
  * 2 SQL INSERTs on node creation
29
26
  * 3 SQL INSERT/UPDATEs on node reparenting
30
27
  * __Support for [concurrency](#concurrency)__ (using [with_advisory_lock](https://github.com/ClosureTree/with_advisory_lock))
31
- * __Tested against ActiveRecord 4.2, 5.0, and 5.1, with Ruby 2.2 and 2.3__
28
+ * __Tested against ActiveRecord 4.2, 5.0, 5.1, 5.2 and 6.0 with Ruby 2.5 and 2.6__
32
29
  * Support for reparenting children (and all their descendants)
33
30
  * Support for [single-table inheritance (STI)](#sti) within the hierarchy
34
31
  * ```find_or_create_by_path``` for [building out heterogeneous hierarchies quickly and conveniently](#find_or_create_by_path)
@@ -341,7 +338,7 @@ When you include ```has_closure_tree``` in your model, you can provide a hash to
341
338
  * ```Tag.find_or_create_by_path(path, attributes)``` returns the node whose name path is ```path```, and will create the node if it doesn't exist already.See (#find_or_create_by_path).
342
339
  * ```Tag.find_all_by_generation(generation_level)``` returns the descendant nodes who are ```generation_level``` away from a root. ```Tag.find_all_by_generation(0)``` is equivalent to ```Tag.roots```.
343
340
  * ```Tag.with_ancestor(ancestors)``` scopes to all descendants whose ancestor is in the given list.
344
-
341
+ * ```Tag.lowest_common_ancestor(descendants)``` finds the lowest common ancestor of the descendants.
345
342
  ### Instance methods
346
343
 
347
344
  * ```tag.root``` returns the root for this node
@@ -665,8 +662,8 @@ end
665
662
 
666
663
  Closure tree is [tested under every valid combination](http://travis-ci.org/#!/ClosureTree/closure_tree) of
667
664
 
668
- * Ruby 2.2, 2.3
669
- * ActiveRecord 4.2, 5.0, and 5.1
665
+ * Ruby 2.5, 2.6
666
+ * ActiveRecord 4.2, 5.x and 6.0
670
667
  * PostgreSQL, MySQL, and SQLite. Concurrency tests are only run with MySQL and PostgreSQL.
671
668
 
672
669
  Assuming you're using [rbenv](https://github.com/sstephenson/rbenv), you can use ```tests.sh``` to
@@ -0,0 +1 @@
1
+ theme: jekyll-theme-leap-day
@@ -1,4 +1,5 @@
1
1
  require 'active_record'
2
+ require 'active_support/core_ext/string/strip'
2
3
 
3
4
  module ClosureTree
4
5
  extend ActiveSupport::Autoload
@@ -99,6 +99,19 @@ module ClosureTree
99
99
  _ct.scope_with_order(scope)
100
100
  end
101
101
 
102
+ def lowest_common_ancestor(*descendants)
103
+ descendants = descendants.first if descendants.length == 1 && descendants.first.respond_to?(:each)
104
+ ancestor_id = hierarchy_class
105
+ .where(descendant_id: descendants)
106
+ .group(:ancestor_id)
107
+ .having("COUNT(ancestor_id) = #{descendants.count}")
108
+ .order(Arel.sql('MIN(generations) ASC'))
109
+ .limit(1)
110
+ .pluck(:ancestor_id).first
111
+
112
+ find_by(primary_key => ancestor_id) if ancestor_id
113
+ end
114
+
102
115
  def find_all_by_generation(generation_level)
103
116
  s = joins(<<-SQL.strip_heredoc)
104
117
  INNER JOIN (
@@ -14,7 +14,7 @@ module ClosureTree
14
14
  ON #{quoted_table_name}.#{model_class.primary_key} = generation_depth.descendant_id
15
15
  SQL
16
16
  scope_with_order(scope.joins(generation_depth), 'generation_depth.depth')
17
- end
17
+ end
18
18
 
19
19
  def hash_tree(tree_scope, limit_depth = nil)
20
20
  limited_scope = limit_depth ? tree_scope.where("#{quoted_hierarchy_table_name}.generations <= #{limit_depth - 1}") : tree_scope
@@ -33,4 +33,4 @@ module ClosureTree
33
33
  tree
34
34
  end
35
35
  end
36
- end
36
+ end
@@ -112,11 +112,28 @@ module ClosureTree
112
112
  # Note that the hierarchy table will be truncated.
113
113
  def rebuild!
114
114
  _ct.with_advisory_lock do
115
- hierarchy_class.delete_all # not destroy_all -- we just want a simple truncate.
115
+ cleanup!
116
116
  roots.find_each { |n| n.send(:rebuild!) } # roots just uses the parent_id column, so this is safe.
117
117
  end
118
118
  nil
119
119
  end
120
+
121
+ def cleanup!
122
+ hierarchy_table = hierarchy_class.arel_table
123
+
124
+ [:descendant_id, :ancestor_id].each do |foreign_key|
125
+ alias_name = foreign_key.to_s.split('_').first + "s"
126
+ alias_table = Arel::Table.new(table_name).alias(alias_name)
127
+ arel_join = hierarchy_table.join(alias_table, Arel::Nodes::OuterJoin)
128
+ .on(alias_table[primary_key].eq(hierarchy_table[foreign_key]))
129
+ .join_sources
130
+
131
+ lonely_childs = hierarchy_class.joins(arel_join).where(alias_table[primary_key].eq(nil))
132
+ ids = lonely_childs.pluck(foreign_key)
133
+
134
+ hierarchy_class.where(hierarchy_table[foreign_key].in(ids)).delete_all
135
+ end
136
+ end
120
137
  end
121
138
  end
122
139
  end
@@ -32,13 +32,15 @@ module ClosureTree
32
32
  end
33
33
 
34
34
  def hierarchy_class_for_model
35
- hierarchy_class = model_class.parent.const_set(short_hierarchy_class_name, Class.new(ActiveRecord::Base))
35
+ parent_class = ActiveSupport::VERSION::MAJOR >= 6 ? model_class.module_parent : model_class.parent
36
+ hierarchy_class = parent_class.const_set(short_hierarchy_class_name, Class.new(ActiveRecord::Base))
36
37
  use_attr_accessible = use_attr_accessible?
37
38
  include_forbidden_attributes_protection = include_forbidden_attributes_protection?
38
- hierarchy_class.class_eval <<-RUBY, __FILE__, __LINE__ + 1
39
+ model_class_name = model_class.to_s
40
+ hierarchy_class.class_eval do
39
41
  include ActiveModel::ForbiddenAttributesProtection if include_forbidden_attributes_protection
40
- belongs_to :ancestor, :class_name => "#{model_class}"
41
- belongs_to :descendant, :class_name => "#{model_class}"
42
+ belongs_to :ancestor, class_name: model_class_name
43
+ belongs_to :descendant, class_name: model_class_name
42
44
  attr_accessible :ancestor, :descendant, :generations if use_attr_accessible
43
45
  def ==(other)
44
46
  self.class == other.class && ancestor_id == other.ancestor_id && descendant_id == other.descendant_id
@@ -47,7 +49,7 @@ module ClosureTree
47
49
  def hash
48
50
  ancestor_id.hash << 31 ^ descendant_id.hash
49
51
  end
50
- RUBY
52
+ end
51
53
  hierarchy_class.table_name = hierarchy_table_name
52
54
  hierarchy_class
53
55
  end
@@ -80,7 +80,7 @@ module ClosureTree
80
80
  end
81
81
 
82
82
  def nulls_last_order_by
83
- "-#{quoted_order_column} #{order_by_order(reverse = true)}"
83
+ "-#{quoted_order_column} #{order_by_order(true)}"
84
84
  end
85
85
 
86
86
  def order_by_order(reverse = false)
@@ -1,3 +1,3 @@
1
1
  module ClosureTree
2
- VERSION = Gem::Version.new('7.0.0')
2
+ VERSION = Gem::Version.new('7.1.0')
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: closure_tree
3
3
  version: !ruby/object:Gem::Version
4
- version: 7.0.0
4
+ version: 7.1.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: 2018-09-23 00:00:00.000000000 Z
11
+ date: 2020-01-13 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord
@@ -153,6 +153,7 @@ files:
153
153
  - MIT-LICENSE
154
154
  - README.md
155
155
  - Rakefile
156
+ - _config.yml
156
157
  - closure_tree.gemspec
157
158
  - lib/closure_tree.rb
158
159
  - lib/closure_tree/active_record_support.rb
@@ -198,8 +199,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
198
199
  - !ruby/object:Gem::Version
199
200
  version: '0'
200
201
  requirements: []
201
- rubyforge_project:
202
- rubygems_version: 2.7.6
202
+ rubygems_version: 3.0.3
203
203
  signing_key:
204
204
  specification_version: 4
205
205
  summary: Easily and efficiently make your ActiveRecord model support hierarchies