Skip to content

Commit

Permalink
Changed test suite to run independently of Rails application
Browse files Browse the repository at this point in the history
  • Loading branch information
stefankroes committed Sep 18, 2010
1 parent 48ddb2e commit f1955bb
Show file tree
Hide file tree
Showing 10 changed files with 540 additions and 473 deletions.
2 changes: 1 addition & 1 deletion README.rdoc
@@ -1,6 +1,6 @@
= Ancestry

Ancestry is a gem/plugin that allows the records of a Ruby on Rails ActiveRecord model to be organised as a tree structure (or hierarchy). It uses a single, intuitively formatted database column, using a variation on the materialised path pattern. It exposes all the standard tree structure relations (ancestors, parent, root, children, siblings, descendants) and all of them can be fetched in a single sql query. Additional features are STI support, named_scopes, depth caching, depth constraints, easy migration from older plugins/gems, integrity checking, integrity restoration, arrangement of (sub)tree into hashes and different strategies for dealing with orphaned records.
Ancestry is a gem/plugin that allows the records of a Ruby on Rails ActiveRecord model to be organised as a tree structure (or hierarchy). It uses a single, intuitively formatted database column, using a variation on the materialised path pattern. It exposes all the standard tree structure relations (ancestors, parent, root, children, siblings, descendants) and all of them can be fetched in a single sql query. Additional features are STI support, scopes, depth caching, depth constraints, easy migration from older plugins/gems, integrity checking, integrity restoration, arrangement of (sub)tree into hashes and different strategies for dealing with orphaned records.

= Installation

Expand Down
15 changes: 13 additions & 2 deletions ancestry.gemspec
Expand Up @@ -5,14 +5,25 @@ Gem::Specification.new do |s|
s.description = 'Organise ActiveRecord model into a tree structure'
s.summary = 'Ancestry allows the records of a ActiveRecord model to be organised in a tree structure, using a single, intuitively formatted database column. It exposes all the standard tree structure relations (ancestors, parent, root, children, siblings, descendants) and all of them can be fetched in a single sql query. Additional features are named_scopes, integrity checking, integrity restoration, arrangement of (sub)tree into hashes and different strategies for dealing with orphaned records.'

s.version = '1.2.0'
s.version = '1.3.0'
s.date = '2010-01-27'

s.author = 'Stefan Kroes'
s.email = 's.a.kroes@gmail.com'
s.homepage = 'http://github.com/stefankroes/ancestry'

s.files = FileList['ancestry.gemspec', '*.rb', 'lib/**/*.rb', 'test/*', 'Rakefile', 'MIT-LICENSE', 'README.rdoc']
s.files = FileList[
'ancestry.gemspec',
'init.rb',
'install.rb',
'lib/ancestry.rb',
'lib/ancestry/has_ancestry.rb',
'lib/ancestry/exceptions.rb',
'lib/ancestry/class_methods.rb',
'lib/ancestry/instance_methods.rb',
'MIT-LICENSE',
'README.rdoc'
]

s.add_dependency 'activerecord', '>= 2.1.0'
end
1 change: 0 additions & 1 deletion install.rb
@@ -1,2 +1 @@
# Install hook code here
puts "Thank you for installing Ancestry. You can visit http://github.com/stefankroes/ancestry to read the documentation."
4 changes: 2 additions & 2 deletions lib/ancestry/class_methods.rb
Expand Up @@ -53,7 +53,7 @@ def check_ancestry_integrity!
# For each node ...
self.base_class.all.each do |node|
# ... check validity of ancestry column
if !node.valid? and node.errors.invalid?(node.class.ancestry_column)
if !node.valid? and node.errors[node.class.ancestry_column].blank?
raise Ancestry::AncestryIntegrityException.new("Invalid format for ancestry column of node #{node.id}: #{node.read_attribute node.ancestry_column}.")
end
# ... check that all ancestors exist
Expand All @@ -78,7 +78,7 @@ def restore_ancestry_integrity!
# For each node ...
self.base_class.all.each do |node|
# ... set its ancestry to nil if invalid
if node.errors.invalid? node.class.ancestry_column
if node.errors[node.class.ancestry_column].blank?
node.without_ancestry_callbacks do
node.update_attributes :ancestry => nil
end
Expand Down
22 changes: 13 additions & 9 deletions lib/ancestry/has_ancestry.rb
Expand Up @@ -36,15 +36,19 @@ def has_ancestry options = {}
# Validate that the ancestor ids don't include own id
validate :ancestry_exclude_self

# Workaround to support Rails 2
scope_method = if ActiveRecord::VERSION::MAJOR < 3 then :named_scope else :scope end


# Named scopes
named_scope :roots, :conditions => {ancestry_column => nil}
named_scope :ancestors_of, lambda { |object| {:conditions => to_node(object).ancestor_conditions} }
named_scope :children_of, lambda { |object| {:conditions => to_node(object).child_conditions} }
named_scope :descendants_of, lambda { |object| {:conditions => to_node(object).descendant_conditions} }
named_scope :subtree_of, lambda { |object| {:conditions => to_node(object).subtree_conditions} }
named_scope :siblings_of, lambda { |object| {:conditions => to_node(object).sibling_conditions} }
named_scope :ordered_by_ancestry, :order => "(case when #{ancestry_column} is null then 0 else 1 end), #{ancestry_column}"
named_scope :ordered_by_ancestry_and, lambda { |order| {:order => "(case when #{ancestry_column} is null then 0 else 1 end), #{ancestry_column}, #{order}"} }
send scope_method, :roots, :conditions => {ancestry_column => nil}
send scope_method, :ancestors_of, lambda { |object| {:conditions => to_node(object).ancestor_conditions} }
send scope_method, :children_of, lambda { |object| {:conditions => to_node(object).child_conditions} }
send scope_method, :descendants_of, lambda { |object| {:conditions => to_node(object).descendant_conditions} }
send scope_method, :subtree_of, lambda { |object| {:conditions => to_node(object).subtree_conditions} }
send scope_method, :siblings_of, lambda { |object| {:conditions => to_node(object).sibling_conditions} }
send scope_method, :ordered_by_ancestry, :order => "(case when #{ancestry_column} is null then 0 else 1 end), #{ancestry_column}"
send scope_method, :ordered_by_ancestry_and, lambda { |order| {:order => "(case when #{ancestry_column} is null then 0 else 1 end), #{ancestry_column}, #{order}"} }

# Update descendants with new ancestry before save
before_save :update_descendants_with_new_ancestry
Expand All @@ -67,7 +71,7 @@ def has_ancestry options = {}

# Create named scopes for depth
{:before_depth => '<', :to_depth => '<=', :at_depth => '=', :from_depth => '>=', :after_depth => '>'}.each do |scope_name, operator|
named_scope scope_name, lambda { |depth|
send scope_method, scope_name, lambda { |depth|
raise Ancestry::AncestryException.new("Named scope '#{scope_name}' is only available when depth caching is enabled.") unless options[:cache_depth]
{:conditions => ["#{depth_cache_column} #{operator} ?", depth]}
}
Expand Down
15 changes: 13 additions & 2 deletions lib/ancestry/instance_methods.rb
@@ -1,8 +1,8 @@
module Ancestry
module InstanceMethods
module InstanceMethods
# Validate that the ancestors don't include itself
def ancestry_exclude_self
errors.add_to_base "#{self.class.name.humanize} cannot be a descendant of itself." if ancestor_ids.include? self.id
add_error_to_base "#{self.class.name.humanize} cannot be a descendant of itself." if ancestor_ids.include? self.id
end

# Update descendants with new ancestry
Expand Down Expand Up @@ -205,5 +205,16 @@ def without_ancestry_callbacks
def ancestry_callbacks_disabled?
!!@disable_ancestry_callbacks
end

private

# Workaround to support Rails 2
def add_error_to_base error
if ActiveRecord::VERSION::MAJOR < 3
errors.add_to_base error
else
errors[:base] << error
end
end
end
end
12 changes: 6 additions & 6 deletions test/database.yml
@@ -1,17 +1,17 @@
sqlite:
adapter: sqlite
database: vendor/plugins/ancestry/test/ancestry_plugin.sqlite.db
database: ":memory:"
sqlite3:
adapter: sqlite3
database: vendor/plugins/ancestry/test/ancestry_plugin.sqlite3.db
database: ":memory:"
postgresql:
adapter: postgresql
database: ancestry_development
database: ancestry_test
username: ancestry
password: ancestry
mysql:
adapter: mysql
host: localhost
username: ancestry_plugin_test
password: ancestry_plugin_test
database: ancestry_plugin_test
database: ancestry_test
username: ancestry
password: ancestry

0 comments on commit f1955bb

Please sign in to comment.