closure_tree 7.0.0 → 7.1.0

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