closure_tree 3.5.2 → 3.6.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.
data/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # Closure Tree [![Build Status](https://secure.travis-ci.org/mceachen/closure_tree.png?branch=master)](http://travis-ci.org/mceachen/closure_tree)
1
+ # Closure Tree
2
2
 
3
3
  Closure Tree is a mostly-API-compatible replacement for the
4
4
  [ancestry](https://github.com/stefankroes/ancestry),
@@ -18,6 +18,17 @@ See [Bill Karwin](http://karwin.blogspot.com/)'s excellent
18
18
  [Models for hierarchical data presentation](http://www.slideshare.net/billkarwin/models-for-hierarchical-data)
19
19
  for a description of different tree storage algorithms.
20
20
 
21
+ ## Table of Contents
22
+
23
+ - [Installation](#installation)
24
+ - [Usage](#usage)
25
+ - [Accessing Data](#accessing-data)
26
+ - [Polymorphic hierarchies with STI](#sti)
27
+ - [Deterministic ordering](#deterministic-ordering)
28
+ - [FAQ](#faq)
29
+ - [Testing](#testing)
30
+ - [Change log](#change-log)
31
+
21
32
  ## Installation
22
33
 
23
34
  Note that closure_tree only supports Rails 3.0 and later, and has test coverage for MySQL, PostgreSQL, and SQLite.
@@ -187,7 +198,8 @@ HT: [ancestry](https://github.com/stefankroes/ancestry#arrangement) and [elhoyos
187
198
  When you include ```acts_as_tree``` in your model, you can provide a hash to override the following defaults:
188
199
 
189
200
  * ```:parent_column_name``` to override the column name of the parent foreign key in the model's table. This defaults to "parent_id".
190
- * ```:hierarchy_table_name``` to override the hierarchy table name. This defaults to the singular name of the model + "_hierarchies".
201
+ * ```:hierarchy_table_name``` to override the hierarchy class name. This defaults to the singular name of the model + "Hierarchy", like ```TagHierarchy```.
202
+ * ```:hierarchy_table_name``` to override the hierarchy table name. This defaults to the singular name of the model + "_hierarchies", like ```tag_hierarchies```.
191
203
  * ```:dependent``` determines what happens when a node is destroyed. Defaults to ```nullify```.
192
204
  * ```:nullify``` will simply set the parent column to null. Each child node will be considered a "root" node. This is the default.
193
205
  * ```:delete_all``` will delete all descendant nodes (which circumvents the destroy hooks)
@@ -321,6 +333,15 @@ root.children.collect(&:name)
321
333
  => ["a", "b", "c"]
322
334
  ```
323
335
 
336
+ ## FAQ
337
+
338
+ ### Does this gem support multiple parents?
339
+
340
+ No. This gem's API is based on the assumption that each node has either 0 or 1 parent.
341
+
342
+ The underlying closure tree structure will support multiple parents, but there would be many
343
+ breaking-API changes to support it. I'm open to suggestions and pull requests.
344
+
324
345
  ## Testing
325
346
 
326
347
  Closure tree is [tested under every combination](http://travis-ci.org/#!/mceachen/closure_tree) of
@@ -331,6 +352,13 @@ Closure tree is [tested under every combination](http://travis-ci.org/#!/mceache
331
352
 
332
353
  ## Change log
333
354
 
355
+ ### 3.6.0
356
+
357
+ * Added support for:
358
+ * ```:hierarchy_class_name``` as an option
359
+ * ActiveRecord::Base.table_name_prefix
360
+ * ActiveRecord::Base.table_name_suffix
361
+
334
362
  ### 3.5.2
335
363
 
336
364
  * Added ```find_all_by_generation```
data/Rakefile CHANGED
@@ -16,5 +16,11 @@ RSpec::Core::RakeTask.new(:spec)
16
16
 
17
17
  task :default => :spec
18
18
 
19
+ task :specs_with_db_ixes do
20
+ [["", ""], ["db_prefix_", ""], ["", "_db_suffix"], ["abc_", "_123"]].each do |prefix, suffix|
21
+ fail unless system("rake spec DB_PREFIX=#{prefix} DB_SUFFIX=#{suffix}")
22
+ end
23
+ end
24
+
19
25
  # Run the specs using all the different database engines:
20
- # for DB in sqlite3 mysql postgresql ; do rake ; done
26
+ # for DB in sqlite3 mysql postgresql ; do rake ; done
@@ -31,6 +31,8 @@ module ClosureTree
31
31
  alias :eql? :==
32
32
  RUBY
33
33
 
34
+ self.hierarchy_class.table_name = hierarchy_table_name
35
+
34
36
  unless order_option.nil?
35
37
  include ClosureTree::DeterministicOrdering
36
38
  include ClosureTree::DeterministicNumericOrdering if order_is_numeric
@@ -388,12 +390,17 @@ module ClosureTree
388
390
  end
389
391
 
390
392
  def hierarchy_table_name
391
- # We need to use the table_name, not ct_class.to_s.demodulize, because they may have overridden the table name
392
- closure_tree_options[:hierarchy_table_name] || ct_table_name.singularize + "_hierarchies"
393
+ # We need to use the table_name, not something like ct_class.to_s.demodulize + "_hierarchies",
394
+ # because they may have overridden the table name, which is what we want to be consistent with
395
+ # in order for the schema to make sense.
396
+ tablename = closure_tree_options[:hierarchy_table_name] ||
397
+ remove_prefix_and_suffix(ct_table_name).singularize + "_hierarchies"
398
+
399
+ ActiveRecord::Base.table_name_prefix + tablename + ActiveRecord::Base.table_name_suffix
393
400
  end
394
401
 
395
402
  def hierarchy_class_name
396
- hierarchy_table_name.singularize.camelize
403
+ closure_tree_options[:hierarchy_class_name] || ct_class.to_s + "Hierarchy"
397
404
  end
398
405
 
399
406
  def quoted_hierarchy_table_name
@@ -445,6 +452,12 @@ module ClosureTree
445
452
  def quoted_table_name
446
453
  connection.quote_column_name ct_table_name
447
454
  end
455
+
456
+ def remove_prefix_and_suffix(table_name)
457
+ prefix = Regexp.escape(ActiveRecord::Base.table_name_prefix)
458
+ suffix = Regexp.escape(ActiveRecord::Base.table_name_suffix)
459
+ table_name.gsub(/^#{prefix}(.+)#{suffix}$/, "\\1")
460
+ end
448
461
  end
449
462
 
450
463
  module DeterministicOrdering
@@ -1,3 +1,3 @@
1
1
  module ClosureTree
2
- VERSION = "3.5.2" unless defined?(::ClosureTree::VERSION)
2
+ VERSION = "3.6.0" unless defined?(::ClosureTree::VERSION)
3
3
  end
@@ -25,6 +25,6 @@ describe CuisineType do
25
25
  end
26
26
 
27
27
  it "sets the table_name of the hierarchy class properly" do
28
- CuisineTypeHierarchy.table_name.should == "cuisine_type_hierarchies"
28
+ CuisineTypeHierarchy.table_name.should == ActiveRecord::Base.table_name_prefix + "cuisine_type_hierarchies" + ActiveRecord::Base.table_name_suffix
29
29
  end
30
30
  end
@@ -1,72 +1,82 @@
1
1
  # encoding: UTF-8
2
+ class ActiveRecord::ConnectionAdapters::AbstractAdapter
3
+ def force_add_index(table_name, columns, options = {})
4
+ begin
5
+ remove_index!(table_name, options[:name])
6
+ rescue ActiveRecord::StatementInvalid, ArgumentError
7
+ end
8
+ add_index table_name, columns, options
9
+ end
10
+ end
11
+
2
12
  ActiveRecord::Schema.define(:version => 0) do
3
13
 
4
14
  create_table "tags", :force => true do |t|
5
- t.string "name"
6
- t.string "title"
7
- t.integer "parent_id"
8
- t.integer "sort_order"
15
+ t.string "name"
16
+ t.string "title"
17
+ t.integer "parent_id"
18
+ t.integer "sort_order"
9
19
  t.datetime "created_at"
10
20
  t.datetime "updated_at"
11
21
  end
12
22
 
13
23
  create_table "tag_hierarchies", :id => false, :force => true do |t|
14
- t.integer "ancestor_id", :null => false
24
+ t.integer "ancestor_id", :null => false
15
25
  t.integer "descendant_id", :null => false
16
- t.integer "generations", :null => false
26
+ t.integer "generations", :null => false
17
27
  end
18
28
 
19
29
  create_table "destroyed_tags", :force => true do |t|
20
- t.string "name"
30
+ t.string "name"
21
31
  end
22
32
 
23
- add_index :tag_hierarchies, [:ancestor_id, :descendant_id], :unique => true
24
- add_index :tag_hierarchies, [:descendant_id]
33
+ force_add_index "tag_hierarchies", [:ancestor_id, :descendant_id], :unique => true, :name => "tag_anc_desc_idx"
34
+ force_add_index "tag_hierarchies", [:descendant_id], :name => "tag_desc_idx"
25
35
 
26
36
  create_table "users", :force => true do |t|
27
- t.string "email"
28
- t.integer "referrer_id"
37
+ t.string "email"
38
+ t.integer "referrer_id"
29
39
  t.datetime "created_at"
30
40
  t.datetime "updated_at"
31
41
  end
32
42
 
33
43
  create_table "contracts", :force => true do |t|
34
- t.integer "user_id", :null => false
44
+ t.integer "user_id", :null => false
35
45
  end
36
46
 
37
47
  create_table "referral_hierarchies", :id => false, :force => true do |t|
38
- t.integer "ancestor_id", :null => false
48
+ t.integer "ancestor_id", :null => false
39
49
  t.integer "descendant_id", :null => false
40
- t.integer "generations", :null => false
50
+ t.integer "generations", :null => false
41
51
  end
42
52
 
43
- add_index :referral_hierarchies, [:ancestor_id, :descendant_id], :unique => true
44
- add_index :referral_hierarchies, [:descendant_id]
53
+ force_add_index "referral_hierarchies", [:ancestor_id, :descendant_id], :unique => true, :name => "ref_anc_desc_idx"
54
+ force_add_index "referral_hierarchies", [:descendant_id], :name => "ref_desc_idx"
45
55
 
46
56
  create_table "labels", :force => true do |t|
47
- t.string "name"
48
- t.string "type"
49
- t.integer "sort_order"
50
- t.integer "mother_id"
57
+ t.string "name"
58
+ t.string "type"
59
+ t.integer "sort_order"
60
+ t.integer "mother_id"
51
61
  end
52
62
 
53
63
  create_table "label_hierarchies", :id => false, :force => true do |t|
54
- t.integer "ancestor_id", :null => false
64
+ t.integer "ancestor_id", :null => false
55
65
  t.integer "descendant_id", :null => false
56
- t.integer "generations", :null => false
66
+ t.integer "generations", :null => false
57
67
  end
58
68
 
59
- add_index :label_hierarchies, [:ancestor_id, :descendant_id], :unique => true
60
- add_index :label_hierarchies, [:descendant_id]
69
+ force_add_index "label_hierarchies", [:ancestor_id, :descendant_id], :unique => true, :name => "lh_anc_desc_idx"
70
+ force_add_index "label_hierarchies", [:descendant_id], :name => "lh_desc_idx"
61
71
 
62
72
  create_table "cuisine_types", :force => true do |t|
63
- t.string "name"
64
- t.integer "parent_id"
73
+ t.string "name"
74
+ t.integer "parent_id"
65
75
  end
66
76
 
67
77
  create_table "cuisine_type_hierarchies", :id => false, :force => true do |t|
68
- t.integer "ancestor_id", :null => false
78
+ t.integer "ancestor_id", :null => false
69
79
  t.integer "descendant_id", :null => false
70
- t.integer "generations", :null => false
80
+ t.integer "generations", :null => false
71
81
  end
72
82
  end
@@ -14,21 +14,19 @@ require 'action_controller' # rspec-rails needs this :(
14
14
 
15
15
  require 'closure_tree'
16
16
 
17
- log = Logger.new(plugin_test_dir + "/debug.log")
18
- log.sev_threshold = Logger::DEBUG
19
- log.datetime_format = "%Y-%m-%d %H:%M:%S"
20
- log.formatter = Logger::Formatter.new
21
-
22
- ActiveRecord::Base.logger = log
17
+ #log = Logger.new(STDOUT)
18
+ #log.sev_threshold = Logger::DEBUG
19
+ #ActiveRecord::Base.logger = log
23
20
 
24
21
  require 'yaml'
25
22
  require 'erb'
26
23
  ENV["DB"] ||= "sqlite3mem"
24
+ ActiveRecord::Base.table_name_prefix = ENV['DB_PREFIX'].to_s
25
+ ActiveRecord::Base.table_name_suffix = ENV['DB_SUFFIX'].to_s
27
26
  ActiveRecord::Base.configurations = YAML::load(ERB.new(IO.read(plugin_test_dir + "/db/database.yml")).result)
28
27
  ActiveRecord::Base.establish_connection(ENV["DB"])
29
28
  ActiveRecord::Migration.verbose = false
30
- load(File.join(plugin_test_dir, "db", "schema.rb"))
31
-
29
+ require 'db/schema'
32
30
  require 'support/models'
33
31
  require 'rspec/rails' # TODO: clean this up-- I don't want to pull the elephant through the mouse hole just for fixture support
34
32
 
@@ -20,6 +20,7 @@ end
20
20
  class User < ActiveRecord::Base
21
21
  acts_as_tree :parent_column_name => "referrer_id",
22
22
  :name_column => 'email',
23
+ :hierarchy_class_name => 'ReferralHierarchy',
23
24
  :hierarchy_table_name => 'referral_hierarchies'
24
25
 
25
26
  has_many :contracts
@@ -390,7 +390,7 @@ end
390
390
  describe "Tag with AR whitelisted attributes enabled" do
391
391
  before(:all) do
392
392
  ActiveRecord::Base.attr_accessible(nil) # turn on whitelisted attributes
393
- ActiveRecord::Base.subclasses.each{|ea|ea.reset_column_information}
393
+ ActiveRecord::Base.descendants.each{|ea|ea.reset_column_information}
394
394
  end
395
395
  it_behaves_like Tag
396
396
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: closure_tree
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.5.2
4
+ version: 3.6.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-09-04 00:00:00.000000000 Z
12
+ date: 2012-09-17 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: activerecord
@@ -192,7 +192,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
192
192
  version: '0'
193
193
  segments:
194
194
  - 0
195
- hash: 4543577055875281407
195
+ hash: 1756781626803345033
196
196
  required_rubygems_version: !ruby/object:Gem::Requirement
197
197
  none: false
198
198
  requirements:
@@ -201,7 +201,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
201
201
  version: '0'
202
202
  segments:
203
203
  - 0
204
- hash: 4543577055875281407
204
+ hash: 1756781626803345033
205
205
  requirements: []
206
206
  rubyforge_project:
207
207
  rubygems_version: 1.8.23