diff --git a/.gitignore b/.gitignore index dbc2bbdc..e2d9fcda 100644 --- a/.gitignore +++ b/.gitignore @@ -11,4 +11,4 @@ tmp/ .rvmrc *.lock tmp/ -.ruby-version +.ruby-* diff --git a/.travis.yml b/.travis.yml index d917e813..7b1b2880 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,6 +9,7 @@ rvm: gemfile: - gemfiles/activerecord_4.1.gemfile - gemfiles/activerecord_4.2.gemfile + - gemfiles/activerecord_5.0.rc1.gemfile - gemfiles/activerecord_edge.gemfile env: diff --git a/Appraisals b/Appraisals index fbd6fd7d..2a33da25 100644 --- a/Appraisals +++ b/Appraisals @@ -8,11 +8,19 @@ end appraise 'activerecord-4.2' do gem 'activerecord', '~> 4.2.0' + platforms :ruby, :rbx do gem 'mysql2', '~> 0.3.20' end end +appraise 'activerecord-5.0.rc1' do + gem 'activerecord', '~> 5.0.0.rc1' + gem 'actionpack', '~> 5.0.0.rc1' + gem 'railties', '~> 5.0.0.rc1' + gem 'rspec-rails', '>= 3.5.0.beta4' +end + appraise 'activerecord-edge' do gem 'activerecord', github: 'rails/rails' gem 'arel', github: 'rails/arel' diff --git a/gemfiles/activerecord_5.0.rc1.gemfile b/gemfiles/activerecord_5.0.rc1.gemfile new file mode 100644 index 00000000..5f1e1f7b --- /dev/null +++ b/gemfiles/activerecord_5.0.rc1.gemfile @@ -0,0 +1,22 @@ +# This file was generated by Appraisal + +source "https://rubygems.org" + +gem "activerecord", "~> 5.0.0.rc1" +gem "actionpack", "~> 5.0.0.rc1" +gem "railties", "~> 5.0.0.rc1" +gem "rspec-rails", ">= 3.5.0.beta4" + +platforms :ruby, :rbx do + gem "mysql2" + gem "pg" + gem "sqlite3" +end + +platforms :jruby do + gem "activerecord-jdbcmysql-adapter" + gem "activerecord-jdbcpostgresql-adapter" + gem "activerecord-jdbcsqlite3-adapter" +end + +gemspec :path => "../" diff --git a/lib/closure_tree/hash_tree.rb b/lib/closure_tree/hash_tree.rb index 385e41b7..7cf4fbe8 100644 --- a/lib/closure_tree/hash_tree.rb +++ b/lib/closure_tree/hash_tree.rb @@ -11,7 +11,7 @@ module ClassMethods # There is no default depth limit. This might be crazy-big, depending # on your tree shape. Hash huge trees at your own peril! def hash_tree(options = {}) - _ct.hash_tree(nil, options[:limit_depth]) + _ct.hash_tree(_ct.default_tree_scope(all, options[:limit_depth])) end end end diff --git a/lib/closure_tree/hash_tree_support.rb b/lib/closure_tree/hash_tree_support.rb index 82d067ae..9904f34b 100644 --- a/lib/closure_tree/hash_tree_support.rb +++ b/lib/closure_tree/hash_tree_support.rb @@ -1,6 +1,6 @@ module ClosureTree module HashTreeSupport - def default_tree_scope(limit_depth = nil) + def default_tree_scope(scope, limit_depth = nil) # Deepest generation, within limit, for each descendant # NOTE: Postgres requires HAVING clauses to always contains aggregate functions (!!) having_clause = limit_depth ? "HAVING MAX(generations) <= #{limit_depth - 1}" : '' @@ -13,15 +13,11 @@ def default_tree_scope(limit_depth = nil) ) AS generation_depth ON #{quoted_table_name}.#{model_class.primary_key} = generation_depth.descendant_id SQL - scope_with_order(model_class.joins(generation_depth), 'generation_depth.depth') + scope_with_order(scope.joins(generation_depth), 'generation_depth.depth') end def hash_tree(tree_scope, limit_depth = nil) - limited_scope = if tree_scope - limit_depth ? tree_scope.where("#{quoted_hierarchy_table_name}.generations <= #{limit_depth - 1}") : tree_scope - else - default_tree_scope(limit_depth) - end + limited_scope = limit_depth ? tree_scope.where("#{quoted_hierarchy_table_name}.generations <= #{limit_depth - 1}") : tree_scope build_hash_tree(limited_scope) end diff --git a/spec/label_spec.rb b/spec/label_spec.rb index cf16be0d..cd99f47f 100644 --- a/spec/label_spec.rb +++ b/spec/label_spec.rb @@ -252,7 +252,7 @@ def name_and_order(enum) end def children_name_and_order - name_and_order(@parent.children(reload = true)) + name_and_order(@parent.children.reload) end def roots_name_and_order @@ -454,7 +454,7 @@ def roots_name_and_order it 'should retain sort orders of descendants when moving to a new parent' do expected_order = ('a'..'z').to_a.shuffle expected_order.map { |ea| first_root.add_child(Label.new(name: ea)) } - actual_order = first_root.children(reload = true).pluck(:name) + actual_order = first_root.children.reload.pluck(:name) expect(actual_order).to eq(expected_order) last_root.append_child(first_root) expect(last_root.self_and_descendants.pluck(:name)).to eq(%w(10 0) + expected_order) @@ -465,13 +465,13 @@ def roots_name_and_order z = first_root.find_or_create_by_path(path) z_children_names = (100..150).to_a.shuffle.map { |ea| ea.to_s } z_children_names.reverse.each { |ea| z.prepend_child(Label.new(name: ea)) } - expect(z.children(reload = true).pluck(:name)).to eq(z_children_names) + expect(z.children.reload.pluck(:name)).to eq(z_children_names) a = first_root.find_by_path(['a']) # move b up to a's level: b = a.children.first a.add_sibling(b) expect(b.parent).to eq(first_root) - expect(z.children(reload = true).pluck(:name)).to eq(z_children_names) + expect(z.children.reload.pluck(:name)).to eq(z_children_names) end end @@ -524,4 +524,31 @@ def roots_name_and_order expect(Label.roots_and_descendants_preordered.collect { |ea| ea.name }).to eq(expected) end end unless sqlite? # sqlite doesn't have a power function. + + context 'hash_tree' do + before do + @a = EventLabel.create(name: 'a') + @b = DateLabel.create(name: 'b') + @c = DirectoryLabel.create(name: 'c') + (1..3).each { |i| DirectoryLabel.create!(name: "c#{ i }", mother_id: @c.id) } + end + it 'should return tree with correct scope when called on class' do + tree = DirectoryLabel.hash_tree + expect(tree.keys.size).to eq(1) + expect(tree.keys.first).to eq(@c) + expect(tree[@c].keys.size).to eq(3) + end + it 'should return tree with correct scope when called on all' do + tree = DirectoryLabel.all.hash_tree + expect(tree.keys.size).to eq(1) + expect(tree.keys.first).to eq(@c) + expect(tree[@c].keys.size).to eq(3) + end + it 'should return tree with correct scope when called on scope chain' do + tree = Label.where(name: 'b').hash_tree + expect(tree.keys.size).to eq(1) + expect(tree.keys.first).to eq(@b) + expect(tree[@b]).to eq({}) + end + end end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 14190f4e..8623dc0d 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -2,7 +2,11 @@ ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__) require 'bundler/setup' if File.exist?(ENV['BUNDLE_GEMFILE']) -require 'rspec' +begin + require 'rspec' +rescue LoadError + # explciitly requiring rspec in ActiveRecord 5+ tests throws exception +end require 'active_record' require 'database_cleaner' require 'closure_tree'