acts_as_recursive_tree 2.2.1 → 3.0.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.
Files changed (49) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ci.yml +37 -0
  3. data/.github/workflows/lint.yml +31 -0
  4. data/.github/workflows/rubygem.yml +37 -0
  5. data/.gitignore +2 -1
  6. data/.rubocop.yml +30 -1
  7. data/.rubocop_todo.yml +28 -281
  8. data/Appraisals +10 -20
  9. data/CHANGELOG.md +10 -1
  10. data/Gemfile +2 -0
  11. data/README.md +3 -0
  12. data/Rakefile +8 -8
  13. data/acts_as_recursive_tree.gemspec +27 -18
  14. data/gemfiles/ar_52.gemfile +8 -0
  15. data/gemfiles/ar_60.gemfile +8 -0
  16. data/gemfiles/ar_61.gemfile +8 -0
  17. data/lib/acts_as_recursive_tree.rb +7 -11
  18. data/lib/acts_as_recursive_tree/acts_macro.rb +6 -6
  19. data/lib/acts_as_recursive_tree/associations.rb +10 -8
  20. data/lib/acts_as_recursive_tree/builders/ancestors.rb +3 -2
  21. data/lib/acts_as_recursive_tree/builders/descendants.rb +3 -1
  22. data/lib/acts_as_recursive_tree/builders/leaves.rb +7 -8
  23. data/lib/acts_as_recursive_tree/builders/relation_builder.rb +14 -10
  24. data/lib/acts_as_recursive_tree/builders/{strategy.rb → strategies.rb} +3 -9
  25. data/lib/acts_as_recursive_tree/builders/{strategy → strategies}/ancestor.rb +3 -1
  26. data/lib/acts_as_recursive_tree/builders/{strategy → strategies}/descendant.rb +3 -1
  27. data/lib/acts_as_recursive_tree/builders/{strategy → strategies}/join.rb +5 -3
  28. data/lib/acts_as_recursive_tree/builders/{strategy → strategies}/subselect.rb +3 -1
  29. data/lib/acts_as_recursive_tree/config.rb +2 -0
  30. data/lib/acts_as_recursive_tree/model.rb +9 -8
  31. data/lib/acts_as_recursive_tree/options/depth_condition.rb +3 -2
  32. data/lib/acts_as_recursive_tree/options/query_options.rb +4 -2
  33. data/lib/acts_as_recursive_tree/options/values.rb +17 -19
  34. data/lib/acts_as_recursive_tree/railtie.rb +2 -0
  35. data/lib/acts_as_recursive_tree/scopes.rb +8 -4
  36. data/lib/acts_as_recursive_tree/version.rb +3 -1
  37. data/spec/builders_spec.rb +17 -11
  38. data/spec/db/database.rb +5 -4
  39. data/spec/db/database.yml +2 -5
  40. data/spec/db/models.rb +12 -11
  41. data/spec/db/schema.rb +3 -4
  42. data/spec/model/location_spec.rb +7 -11
  43. data/spec/model/node_spec.rb +35 -49
  44. data/spec/model/relation_spec.rb +6 -11
  45. data/spec/spec_helper.rb +54 -55
  46. data/spec/values_spec.rb +21 -17
  47. metadata +115 -33
  48. data/lib/acts_as_recursive_tree/builders.rb +0 -14
  49. data/lib/acts_as_recursive_tree/options.rb +0 -9
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'spec_helper'
2
4
 
3
5
  describe Location do
@@ -10,7 +12,6 @@ describe Location do
10
12
  @building.children << floor
11
13
 
12
14
  1.upto(5) do |index_room|
13
-
14
15
  floor.children << Room.create!(name: "#{index_room}. Room")
15
16
  end
16
17
  end
@@ -22,34 +23,29 @@ describe Location do
22
23
  end
23
24
 
24
25
  context '::descendants_of' do
25
-
26
26
  context 'with Room' do
27
27
  let(:rooms) { Room.descendants_of(@building) }
28
28
 
29
- it 'should have 25 rooms' do
29
+ it 'has 25 rooms' do
30
30
  expect(rooms.count).to eq(25)
31
31
  end
32
32
 
33
- it 'should all be of type Room' do
33
+ it 'alls be of type Room' do
34
34
  expect(rooms.all).to all(be_an(Room))
35
35
  end
36
-
37
36
  end
38
37
 
39
38
  context 'with Floor' do
40
39
  let(:floors) { Floor.descendants_of(@building) }
41
40
 
42
- it 'should have 5 Floors' do
41
+ it 'has 5 Floors' do
43
42
  expect(floors.count).to eq(5)
44
43
  end
45
44
 
46
- it 'should all be of type Floor' do
45
+ it 'alls be of type Floor' do
47
46
  expect(floors.all).to all(be_an(Floor))
48
47
  end
49
-
50
48
  end
51
-
52
49
  end
53
50
  end
54
-
55
- end
51
+ end
@@ -1,12 +1,10 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'spec_helper'
2
4
 
3
5
  describe Node do
4
-
5
6
  def create_tree(max_level, current_level = 0, node = nil)
6
-
7
- if node.nil?
8
- node = Node.create!(name: 'root')
9
- end
7
+ node = Node.create!(name: 'root') if node.nil?
10
8
 
11
9
  1.upto(max_level - current_level) do |index|
12
10
  child = node.children.create!(name: "child #{index} - level #{current_level}")
@@ -21,80 +19,72 @@ describe Node do
21
19
  @child = @root.children.first
22
20
  end
23
21
 
24
- context '#children' do
25
- it 'should have 3 children' do
26
- expect(@root.children.count).to eql(3)
22
+ describe '#children' do
23
+ it 'has 3 children' do
24
+ expect(@root.children.count).to be(3)
27
25
  end
28
26
 
29
- it 'should not include root node ' do
30
- expect(@root.children).to_not include(@root)
27
+ it 'does not include root node ' do
28
+ expect(@root.children).not_to include(@root)
31
29
  end
32
-
33
30
  end
34
31
 
35
- context '#descendants' do
36
-
37
- it 'should have 15 descendants' do
32
+ describe '#descendants' do
33
+ it 'has 15 descendants' do
38
34
  expect(@root.descendants.count).to eql(3 + (3 * 2) + (3 * 2 * 1))
39
35
  end
40
36
 
41
- it 'should not include root' do
42
- expect(@root.descendants).to_not include(@root)
37
+ it 'does not include root' do
38
+ expect(@root.descendants).not_to include(@root)
43
39
  end
44
40
  end
45
- context '#self_and_descendants' do
46
41
 
47
- it 'should have 15 descendants and self' do
42
+ describe '#self_and_descendants' do
43
+ it 'has 15 descendants and self' do
48
44
  expect(@root.self_and_descendants.count).to eql(@root.descendants.count + 1)
49
45
  end
50
46
 
51
- it 'should include self' do
47
+ it 'includes self' do
52
48
  expect(@root.self_and_descendants.all).to include(@root)
53
49
  end
54
50
  end
55
51
 
56
- context '#root?' do
57
-
58
- it 'should be true for root node' do
59
- expect(@root.root?).to be_truthy
52
+ describe '#root?' do
53
+ it 'is true for root node' do
54
+ expect(@root).to be_root
60
55
  end
61
56
 
62
- it 'should be false for children' do
63
- expect(@child.root?).to be_falsey
57
+ it 'is false for children' do
58
+ expect(@child).not_to be_root
64
59
  end
65
-
66
60
  end
67
61
 
68
- context '#leaf?' do
69
-
70
- it 'should be false for root node' do
71
- expect(@root.leaf?).to be_falsey
62
+ describe '#leaf?' do
63
+ it 'is false for root node' do
64
+ expect(@root).not_to be_leaf
72
65
  end
73
66
 
74
- it 'should be true for children' do
75
- expect(@root.leaves.first.leaf?).to be_truthy
67
+ it 'is true for children' do
68
+ expect(@root.leaves.first).to be_leaf
76
69
  end
77
-
78
70
  end
79
71
 
80
-
81
- context '#leaves' do
82
- it 'should have 6 leaves' do
83
- expect(@root.leaves.count).to eql(6)
72
+ describe '#leaves' do
73
+ it 'has 6 leaves' do
74
+ expect(@root.leaves.count).to be(6)
84
75
  end
85
76
  end
86
77
 
87
78
  describe 'child' do
88
-
89
- it 'should have root as parent' do
79
+ it 'has root as parent' do
90
80
  expect(@child.parent).to eql(@root)
91
81
  end
92
82
 
93
- it 'should have 1 ancestor' do
94
- expect(@child.ancestors.count).to eql(1)
83
+ it 'has 1 ancestor' do
84
+ expect(@child.ancestors.count).to be(1)
95
85
  end
96
86
 
97
- it 'should have root as only ancestor' do
87
+ it 'has root as only ancestor' do
98
88
  expect(@child.ancestors.first).to eql(@root)
99
89
  end
100
90
 
@@ -111,19 +101,15 @@ describe Node do
111
101
  end
112
102
  end
113
103
 
114
-
115
104
  describe 'scopes' do
116
-
117
105
  context 'roots' do
118
-
119
106
  it 'has only one root node' do
120
- expect(Node.roots.count).to eql(1)
107
+ expect(described_class.roots.count).to be(1)
121
108
  end
122
109
 
123
110
  it 'is the @root node' do
124
- expect(Node.roots.first).to eql(@root)
111
+ expect(described_class.roots.first).to eql(@root)
125
112
  end
126
113
  end
127
-
128
114
  end
129
- end
115
+ end
@@ -1,12 +1,10 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'spec_helper'
2
4
 
3
5
  describe 'Relation' do
4
-
5
6
  def create_tree(max_level, current_level: 0, node: nil, stop_at: nil)
6
-
7
- if node.nil?
8
- node = Node.create!(name: 'root')
9
- end
7
+ node = Node.create!(name: 'root') if node.nil?
10
8
 
11
9
  1.upto(max_level - current_level) do |index|
12
10
  child = node.children.create!(name: "child #{index} - level #{current_level}", active: stop_at > current_level)
@@ -23,7 +21,6 @@ describe 'Relation' do
23
21
  end
24
22
 
25
23
  context 'descendants' do
26
-
27
24
  it 'works with simple relation' do
28
25
  desc = @root.descendants { |opts| opts.condition = Node.where(active: true) }
29
26
  desc.all.each do |node|
@@ -40,7 +37,6 @@ describe 'Relation' do
40
37
  end
41
38
 
42
39
  context 'ancestors' do
43
-
44
40
  it 'works with simple relation' do
45
41
  ancestors = @root.leaves.first.ancestors { |opts| opts.condition = Node.where(active: false) }.to_a
46
42
 
@@ -48,7 +44,7 @@ describe 'Relation' do
48
44
  expect(node.active).to be_falsey
49
45
  end
50
46
 
51
- expect(ancestors).to_not include(@root)
47
+ expect(ancestors).not_to include(@root)
52
48
  end
53
49
 
54
50
  it 'works with joins relation' do
@@ -56,8 +52,7 @@ describe 'Relation' do
56
52
  ancestors.all.each do |node|
57
53
  expect(node.node_info.status).to eql('bar')
58
54
  end
59
- expect(ancestors).to_not include(@root)
55
+ expect(ancestors).not_to include(@root)
60
56
  end
61
57
  end
62
-
63
- end
58
+ end
data/spec/spec_helper.rb CHANGED
@@ -1,6 +1,8 @@
1
- $LOAD_PATH.unshift(File.dirname(__FILE__) + '/../lib')
1
+ # frozen_string_literal: true
2
2
 
3
- ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__)
3
+ $LOAD_PATH.unshift("#{File.dirname(__FILE__)}/../lib")
4
+
5
+ ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../Gemfile', __dir__)
4
6
  require 'bundler/setup' if File.exist?(ENV['BUNDLE_GEMFILE'])
5
7
  require 'active_record'
6
8
 
@@ -9,7 +11,6 @@ require_relative 'db/database'
9
11
 
10
12
  require 'database_cleaner'
11
13
 
12
-
13
14
  # This file was generated by the `rspec --init` command. Conventionally, all
14
15
  # specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
15
16
  # The generated `.rspec` file contains `--require spec_helper` which will cause
@@ -54,64 +55,62 @@ RSpec.configure do |config|
54
55
 
55
56
  # The settings below are suggested to provide a good initial experience
56
57
  # with RSpec, but feel free to customize to your heart's content.
57
- =begin
58
- # These two settings work together to allow you to limit a spec run
59
- # to individual examples or groups you care about by tagging them with
60
- # `:focus` metadata. When nothing is tagged with `:focus`, all examples
61
- # get run.
62
- config.filter_run :focus
63
- config.run_all_when_everything_filtered = true
64
-
65
- # Allows RSpec to persist some state between runs in order to support
66
- # the `--only-failures` and `--next-failure` CLI options. We recommend
67
- # you configure your source control system to ignore this file.
68
- config.example_status_persistence_file_path = "spec/examples.txt"
69
-
70
- # Limits the available syntax to the non-monkey patched syntax that is
71
- # recommended. For more details, see:
72
- # - http://myronmars.to/n/dev-blog/2012/06/rspecs-new-expectation-syntax
73
- # - http://www.teaisaweso.me/blog/2013/05/27/rspecs-new-message-expectation-syntax/
74
- # - http://myronmars.to/n/dev-blog/2014/05/notable-changes-in-rspec-3#new__config_option_to_disable_rspeccore_monkey_patching
75
- config.disable_monkey_patching!
76
-
77
- # This setting enables warnings. It's recommended, but in some cases may
78
- # be too noisy due to issues in dependencies.
79
- config.warnings = true
80
-
81
- # Many RSpec users commonly either run the entire suite or an individual
82
- # file, and it's useful to allow more verbose output when running an
83
- # individual spec file.
84
- if config.files_to_run.one?
85
- # Use the documentation formatter for detailed output,
86
- # unless a formatter has already been configured
87
- # (e.g. via a command-line flag).
88
- config.default_formatter = 'doc'
89
- end
90
-
91
- # Print the 10 slowest examples and example groups at the
92
- # end of the spec run, to help surface which specs are running
93
- # particularly slow.
94
- config.profile_examples = 10
95
-
96
- # Run specs in random order to surface order dependencies. If you find an
97
- # order dependency and want to debug it, you can fix the order by providing
98
- # the seed, which is printed after each run.
99
- # --seed 1234
100
- config.order = :random
101
-
102
- # Seed global randomization in this process using the `--seed` CLI option.
103
- # Setting this allows you to use `--seed` to deterministically reproduce
104
- # test failures related to randomization by passing the same `--seed` value
105
- # as the one that triggered the failure.
106
- Kernel.srand config.seed
107
- =end
58
+ # # These two settings work together to allow you to limit a spec run
59
+ # # to individual examples or groups you care about by tagging them with
60
+ # # `:focus` metadata. When nothing is tagged with `:focus`, all examples
61
+ # # get run.
62
+ # config.filter_run :focus
63
+ # config.run_all_when_everything_filtered = true
64
+ #
65
+ # # Allows RSpec to persist some state between runs in order to support
66
+ # # the `--only-failures` and `--next-failure` CLI options. We recommend
67
+ # # you configure your source control system to ignore this file.
68
+ # config.example_status_persistence_file_path = "spec/examples.txt"
69
+ #
70
+ # # Limits the available syntax to the non-monkey patched syntax that is
71
+ # # recommended. For more details, see:
72
+ # # - http://myronmars.to/n/dev-blog/2012/06/rspecs-new-expectation-syntax
73
+ # # - http://www.teaisaweso.me/blog/2013/05/27/rspecs-new-message-expectation-syntax/
74
+ # # - http://myronmars.to/n/dev-blog/2014/05/notable-changes-in-rspec-3#new__config_option_to_disable_rspeccore_monkey_patching
75
+ # config.disable_monkey_patching!
76
+ #
77
+ # # This setting enables warnings. It's recommended, but in some cases may
78
+ # # be too noisy due to issues in dependencies.
79
+ # config.warnings = true
80
+ #
81
+ # # Many RSpec users commonly either run the entire suite or an individual
82
+ # # file, and it's useful to allow more verbose output when running an
83
+ # # individual spec file.
84
+ # if config.files_to_run.one?
85
+ # # Use the documentation formatter for detailed output,
86
+ # # unless a formatter has already been configured
87
+ # # (e.g. via a command-line flag).
88
+ # config.default_formatter = 'doc'
89
+ # end
90
+ #
91
+ # # Print the 10 slowest examples and example groups at the
92
+ # # end of the spec run, to help surface which specs are running
93
+ # # particularly slow.
94
+ # config.profile_examples = 10
95
+ #
96
+ # # Run specs in random order to surface order dependencies. If you find an
97
+ # # order dependency and want to debug it, you can fix the order by providing
98
+ # # the seed, which is printed after each run.
99
+ # # --seed 1234
100
+ # config.order = :random
101
+ #
102
+ # # Seed global randomization in this process using the `--seed` CLI option.
103
+ # # Setting this allows you to use `--seed` to deterministically reproduce
104
+ # # test failures related to randomization by passing the same `--seed` value
105
+ # # as the one that triggered the failure.
106
+ # Kernel.srand config.seed
108
107
 
109
108
  config.before(:suite) do
110
109
  DatabaseCleaner.strategy = :transaction
111
110
  DatabaseCleaner.clean_with(:truncation)
112
111
  end
113
112
 
114
- config.around(:each) do |example|
113
+ config.around do |example|
115
114
  DatabaseCleaner.cleaning do
116
115
  example.run
117
116
  end
data/spec/values_spec.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'spec_helper'
2
4
 
3
5
  shared_examples 'single values' do
@@ -5,11 +7,11 @@ shared_examples 'single values' do
5
7
 
6
8
  it { is_expected.to be_a ActsAsRecursiveTree::Options::Values::SingleValue }
7
9
 
8
- it 'should apply_to' do
10
+ it 'apply_toes' do
9
11
  expect(value.apply_to(attribute).to_sql).to end_with " = #{single_value}"
10
12
  end
11
13
 
12
- it 'should apply_negated_to' do
14
+ it 'apply_negated_toes' do
13
15
  expect(value.apply_negated_to(attribute).to_sql).to end_with " != #{single_value}"
14
16
  end
15
17
  end
@@ -19,8 +21,8 @@ describe ActsAsRecursiveTree::Options::Values do
19
21
  let(:attribute) { table['test_attr'] }
20
22
 
21
23
  context 'invalid agurment' do
22
- it 'should raise exception' do
23
- expect{described_class.create(nil)}.to raise_exception /is not supported/
24
+ it 'raises exception' do
25
+ expect { described_class.create(nil) }.to raise_exception(/is not supported/)
24
26
  end
25
27
  end
26
28
 
@@ -34,52 +36,54 @@ describe ActsAsRecursiveTree::Options::Values do
34
36
  it_behaves_like 'single values' do
35
37
  let(:value_obj) { Node.new(id: single_value) }
36
38
  end
37
-
38
39
  end
39
40
 
40
41
  context 'multi value' do
41
42
  context 'Array' do
42
- let(:array) { [1, 2, 3] }
43
43
  subject(:value) { described_class.create(array) }
44
44
 
45
+ let(:array) { [1, 2, 3] }
46
+
45
47
  it { is_expected.to be_a ActsAsRecursiveTree::Options::Values::MultiValue }
46
48
 
47
- it 'should apply_to' do
49
+ it 'apply_toes' do
48
50
  expect(value.apply_to(attribute).to_sql).to end_with " IN (#{array.join(', ')})"
49
51
  end
50
52
 
51
- it 'should apply_negated_to' do
53
+ it 'apply_negated_toes' do
52
54
  expect(value.apply_negated_to(attribute).to_sql).to end_with " NOT IN (#{array.join(', ')})"
53
55
  end
54
56
  end
55
57
 
56
58
  context 'Range' do
57
- let(:range) { 1..3 }
58
59
  subject(:value) { described_class.create(range) }
59
60
 
61
+ let(:range) { 1..3 }
62
+
60
63
  it { is_expected.to be_a ActsAsRecursiveTree::Options::Values::RangeValue }
61
64
 
62
- it 'should apply_to' do
65
+ it 'apply_toes' do
63
66
  expect(value.apply_to(attribute).to_sql).to end_with "BETWEEN #{range.begin} AND #{range.end}"
64
67
  end
65
68
 
66
- it 'should apply_negated_to' do
67
- expect(value.apply_negated_to(attribute).to_sql).to match /< #{range.begin} OR.* > #{range.end}/
69
+ it 'apply_negated_toes' do
70
+ expect(value.apply_negated_to(attribute).to_sql).to match(/< #{range.begin} OR.* > #{range.end}/)
68
71
  end
69
72
  end
70
73
 
71
74
  context 'Relation' do
72
- let(:relation) { Node.where(name: 'test') }
73
75
  subject(:value) { described_class.create(relation, OpenStruct.new(primary_key: :id)) }
74
76
 
77
+ let(:relation) { Node.where(name: 'test') }
78
+
75
79
  it { is_expected.to be_a ActsAsRecursiveTree::Options::Values::Relation }
76
80
 
77
- it 'should apply_to' do
78
- expect(value.apply_to(attribute).to_sql).to match /IN \(SELECT.*\)/
81
+ it 'apply_toes' do
82
+ expect(value.apply_to(attribute).to_sql).to match(/IN \(SELECT.*\)/)
79
83
  end
80
84
 
81
- it 'should apply_negated_to' do
82
- expect(value.apply_negated_to(attribute).to_sql).to match /NOT IN \(SELECT.*\)/
85
+ it 'apply_negated_toes' do
86
+ expect(value.apply_negated_to(attribute).to_sql).to match(/NOT IN \(SELECT.*\)/)
83
87
  end
84
88
  end
85
89
  end