collectiveidea-awesome_nested_set 1.2.0 → 1.3.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.rdoc +18 -3
- data/Rakefile +2 -2
- data/VERSION +1 -1
- data/awesome_nested_set.gemspec +4 -4
- data/lib/awesome_nested_set.rb +21 -9
- data/rails/init.rb +0 -1
- data/test/application.rb +1 -0
- data/test/awesome_nested_set/helper_test.rb +3 -3
- data/test/awesome_nested_set_test.rb +57 -8
- data/test/test_helper.rb +6 -6
- metadata +6 -5
- data/lib/awesome_nested_set/compatability.rb +0 -29
- data/lib/awesome_nested_set/named_scope.rb +0 -140
data/README.rdoc
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
= AwesomeNestedSet
|
2
2
|
|
3
|
-
Awesome Nested Set is an implementation of the nested set pattern for ActiveRecord models. It is replacement for acts_as_nested_set and BetterNestedSet, but awesomer.
|
3
|
+
Awesome Nested Set is an implementation of the nested set pattern for ActiveRecord models. It is replacement for acts_as_nested_set and BetterNestedSet, but awesomer. It supports Rails 2.1 and later.
|
4
4
|
|
5
5
|
== What makes this so awesome?
|
6
6
|
|
@@ -8,7 +8,7 @@ This is a new implementation of nested set based off of BetterNestedSet that fix
|
|
8
8
|
|
9
9
|
== Installation
|
10
10
|
|
11
|
-
|
11
|
+
Install as a plugin:
|
12
12
|
|
13
13
|
script/plugin install git://github.com/collectiveidea/awesome_nested_set.git
|
14
14
|
|
@@ -60,5 +60,20 @@ You can learn more about nested sets at:
|
|
60
60
|
http://api.rubyonrails.com/classes/ActiveRecord/Acts/NestedSet/ClassMethods.html
|
61
61
|
http://opensource.symetrie.com/trac/better_nested_set/
|
62
62
|
|
63
|
+
== How to contribute
|
63
64
|
|
64
|
-
|
65
|
+
If you find what you might think is a bug:
|
66
|
+
|
67
|
+
1. Check the GitHub issue tracker to see if anyone else has had the same issue.
|
68
|
+
http://github.com/collectiveidea/awesome_nested_set/issues/
|
69
|
+
2. If you don't see anything, create an issue with information on how to reproduce it.
|
70
|
+
|
71
|
+
If you want to contribute an enhancement or a fix:
|
72
|
+
|
73
|
+
1. Fork the project on github.
|
74
|
+
http://github.com/collectiveidea/awesome_nested_set/
|
75
|
+
2. Make your changes with tests.
|
76
|
+
3. Commit the changes without making changes to the Rakefile, VERSION, or any other files that aren't related to your enhancement or fix
|
77
|
+
4. Send a pull request.
|
78
|
+
|
79
|
+
Copyright ©2008 Collective Idea, released under the MIT license
|
data/Rakefile
CHANGED
@@ -28,7 +28,7 @@ task :default => :test
|
|
28
28
|
|
29
29
|
desc 'Test the awesome_nested_set plugin.'
|
30
30
|
Rake::TestTask.new(:test) do |t|
|
31
|
-
t.libs
|
31
|
+
t.libs += ['lib', 'test']
|
32
32
|
t.pattern = 'test/**/*_test.rb'
|
33
33
|
t.verbose = true
|
34
34
|
end
|
@@ -45,7 +45,7 @@ end
|
|
45
45
|
namespace :test do
|
46
46
|
desc "just rcov minus html output"
|
47
47
|
Rcov::RcovTask.new(:coverage) do |t|
|
48
|
-
|
48
|
+
t.libs << 'test'
|
49
49
|
t.test_files = FileList['test/**/*_test.rb']
|
50
50
|
t.output_dir = 'coverage'
|
51
51
|
t.verbose = true
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
1.
|
1
|
+
1.3.0
|
data/awesome_nested_set.gemspec
CHANGED
@@ -2,11 +2,11 @@
|
|
2
2
|
|
3
3
|
Gem::Specification.new do |s|
|
4
4
|
s.name = %q{awesome_nested_set}
|
5
|
-
s.version = "1.
|
5
|
+
s.version = "1.3.0"
|
6
6
|
|
7
7
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
8
8
|
s.authors = ["Brandon Keepers", "Daniel Morrison"]
|
9
|
-
s.date = %q{2009-
|
9
|
+
s.date = %q{2009-08-11}
|
10
10
|
s.description = %q{An awesome nested set implementation for Active Record}
|
11
11
|
s.email = %q{info@collectiveidea.com}
|
12
12
|
s.extra_rdoc_files = [
|
@@ -22,10 +22,9 @@ Gem::Specification.new do |s|
|
|
22
22
|
"awesome_nested_set.gemspec",
|
23
23
|
"init.rb",
|
24
24
|
"lib/awesome_nested_set.rb",
|
25
|
-
"lib/awesome_nested_set/compatability.rb",
|
26
25
|
"lib/awesome_nested_set/helper.rb",
|
27
|
-
"lib/awesome_nested_set/named_scope.rb",
|
28
26
|
"rails/init.rb",
|
27
|
+
"test/application.rb",
|
29
28
|
"test/awesome_nested_set/helper_test.rb",
|
30
29
|
"test/awesome_nested_set_test.rb",
|
31
30
|
"test/db/database.yml",
|
@@ -46,6 +45,7 @@ Gem::Specification.new do |s|
|
|
46
45
|
"test/fixtures/categories.yml",
|
47
46
|
"test/fixtures/departments.yml",
|
48
47
|
"test/fixtures/notes.yml",
|
48
|
+
"test/application.rb",
|
49
49
|
"test/awesome_nested_set/helper_test.rb",
|
50
50
|
"test/awesome_nested_set_test.rb",
|
51
51
|
"test/db/schema.rb",
|
data/lib/awesome_nested_set.rb
CHANGED
@@ -72,19 +72,23 @@ module CollectiveIdea #:nodoc:
|
|
72
72
|
include InstanceMethods
|
73
73
|
extend Columns
|
74
74
|
extend ClassMethods
|
75
|
+
|
76
|
+
belongs_to :parent, :class_name => self.base_class.class_name,
|
77
|
+
:foreign_key => parent_column_name
|
75
78
|
|
76
79
|
attr_accessor :skip_before_destroy
|
77
80
|
|
78
81
|
# no bulk assignment
|
79
82
|
attr_protected left_column_name.intern,
|
80
|
-
right_column_name.intern
|
81
|
-
parent_column_name.intern
|
83
|
+
right_column_name.intern
|
82
84
|
|
83
|
-
before_create
|
85
|
+
before_create :set_default_left_and_right
|
86
|
+
before_save :store_new_parent
|
87
|
+
after_save :move_to_new_parent
|
84
88
|
before_destroy :destroy_descendants
|
85
89
|
|
86
90
|
# no assignment to structure fields
|
87
|
-
[left_column_name, right_column_name
|
91
|
+
[left_column_name, right_column_name].each do |column|
|
88
92
|
module_eval <<-"end_eval", __FILE__, __LINE__
|
89
93
|
def #{column}=(x)
|
90
94
|
raise ActiveRecord::ActiveRecordError, "Unauthorized assignment to #{column}: it's an internal field handled by acts_as_nested_set code, use move_to_* methods instead."
|
@@ -283,11 +287,6 @@ module CollectiveIdea #:nodoc:
|
|
283
287
|
self_and_ancestors.find(:first)
|
284
288
|
end
|
285
289
|
|
286
|
-
# Returns the immediate parent
|
287
|
-
def parent
|
288
|
-
nested_set_scope.find_by_id(parent_id) if parent_id
|
289
|
-
end
|
290
|
-
|
291
290
|
# Returns the array of all parents and self
|
292
291
|
def self_and_ancestors
|
293
292
|
nested_set_scope.scoped :conditions => [
|
@@ -434,6 +433,19 @@ module CollectiveIdea #:nodoc:
|
|
434
433
|
self.class.base_class.scoped options
|
435
434
|
end
|
436
435
|
|
436
|
+
def store_new_parent
|
437
|
+
@move_to_new_parent_id = parent_id_changed? ? parent_id : false
|
438
|
+
true # force callback to return true
|
439
|
+
end
|
440
|
+
|
441
|
+
def move_to_new_parent
|
442
|
+
if @move_to_new_parent_id.nil?
|
443
|
+
move_to_root
|
444
|
+
elsif @move_to_new_parent_id
|
445
|
+
move_to_child_of(@move_to_new_parent_id)
|
446
|
+
end
|
447
|
+
end
|
448
|
+
|
437
449
|
# on creation, set automatically lft and rgt to the end of the tree
|
438
450
|
def set_default_left_and_right
|
439
451
|
maxright = nested_set_scope.maximum(right_column_name) || 0
|
data/rails/init.rb
CHANGED
data/test/application.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
# This file is here to satisfy test_help from Rails < 2.3
|
@@ -1,9 +1,9 @@
|
|
1
|
-
require
|
1
|
+
require 'test_helper'
|
2
2
|
|
3
3
|
module CollectiveIdea
|
4
4
|
module Acts #:nodoc:
|
5
5
|
module NestedSet #:nodoc:
|
6
|
-
class AwesomeNestedSetTest <
|
6
|
+
class AwesomeNestedSetTest < TestCaseClass
|
7
7
|
include Helper
|
8
8
|
fixtures :categories
|
9
9
|
|
@@ -38,4 +38,4 @@ module CollectiveIdea
|
|
38
38
|
end
|
39
39
|
end
|
40
40
|
end
|
41
|
-
end
|
41
|
+
end
|
@@ -1,10 +1,10 @@
|
|
1
|
-
require
|
1
|
+
require 'test_helper'
|
2
2
|
|
3
3
|
class Note < ActiveRecord::Base
|
4
4
|
acts_as_nested_set :scope => [:notable_id, :notable_type]
|
5
5
|
end
|
6
6
|
|
7
|
-
class AwesomeNestedSetTest <
|
7
|
+
class AwesomeNestedSetTest < TestCaseClass
|
8
8
|
|
9
9
|
class Default < ActiveRecord::Base
|
10
10
|
acts_as_nested_set
|
@@ -66,15 +66,10 @@ class AwesomeNestedSetTest < Test::Unit::TestCase
|
|
66
66
|
assert_raises(ActiveRecord::ActiveRecordError) { Category.new.rgt = 1 }
|
67
67
|
end
|
68
68
|
|
69
|
-
def test_parent_column_protected_from_assignment
|
70
|
-
assert_raises(ActiveRecord::ActiveRecordError) { Category.new.parent_id = 1 }
|
71
|
-
end
|
72
|
-
|
73
69
|
def test_colums_protected_on_initialize
|
74
|
-
c = Category.new(:lft => 1, :rgt => 2
|
70
|
+
c = Category.new(:lft => 1, :rgt => 2)
|
75
71
|
assert_nil c.lft
|
76
72
|
assert_nil c.rgt
|
77
|
-
assert_nil c.parent_id
|
78
73
|
end
|
79
74
|
|
80
75
|
def test_scoped_appends_id
|
@@ -619,4 +614,58 @@ class AwesomeNestedSetTest < Test::Unit::TestCase
|
|
619
614
|
assert Category.valid?
|
620
615
|
end
|
621
616
|
|
617
|
+
def test_assigning_parent_id_on_create
|
618
|
+
category = Category.create!(:name => "Child", :parent_id => categories(:child_2).id)
|
619
|
+
assert_equal categories(:child_2), category.parent
|
620
|
+
assert_equal categories(:child_2).id, category.parent_id
|
621
|
+
assert_not_nil category.left
|
622
|
+
assert_not_nil category.right
|
623
|
+
assert Category.valid?
|
624
|
+
end
|
625
|
+
|
626
|
+
def test_assigning_parent_on_create
|
627
|
+
category = Category.create!(:name => "Child", :parent => categories(:child_2))
|
628
|
+
assert_equal categories(:child_2), category.parent
|
629
|
+
assert_equal categories(:child_2).id, category.parent_id
|
630
|
+
assert_not_nil category.left
|
631
|
+
assert_not_nil category.right
|
632
|
+
assert Category.valid?
|
633
|
+
end
|
634
|
+
|
635
|
+
def test_assigning_parent_id_to_nil_on_create
|
636
|
+
category = Category.create!(:name => "New Root", :parent_id => nil)
|
637
|
+
assert_nil category.parent
|
638
|
+
assert_nil category.parent_id
|
639
|
+
assert_not_nil category.left
|
640
|
+
assert_not_nil category.right
|
641
|
+
assert Category.valid?
|
642
|
+
end
|
643
|
+
|
644
|
+
def test_assigning_parent_id_on_update
|
645
|
+
category = categories(:child_2_1)
|
646
|
+
category.parent_id = categories(:child_3).id
|
647
|
+
category.save
|
648
|
+
assert_equal categories(:child_3), category.parent
|
649
|
+
assert_equal categories(:child_3).id, category.parent_id
|
650
|
+
assert Category.valid?
|
651
|
+
end
|
652
|
+
|
653
|
+
def test_assigning_parent_on_update
|
654
|
+
category = categories(:child_2_1)
|
655
|
+
category.parent = categories(:child_3)
|
656
|
+
category.save
|
657
|
+
assert_equal categories(:child_3), category.parent
|
658
|
+
assert_equal categories(:child_3).id, category.parent_id
|
659
|
+
assert Category.valid?
|
660
|
+
end
|
661
|
+
|
662
|
+
def test_assigning_parent_id_to_nil_on_update
|
663
|
+
category = categories(:child_2_1)
|
664
|
+
category.parent_id = nil
|
665
|
+
category.save
|
666
|
+
assert_nil category.parent
|
667
|
+
assert_nil category.parent_id
|
668
|
+
assert Category.valid?
|
669
|
+
end
|
670
|
+
|
622
671
|
end
|
data/test/test_helper.rb
CHANGED
@@ -1,16 +1,16 @@
|
|
1
1
|
$:.unshift(File.dirname(__FILE__) + '/../lib')
|
2
2
|
plugin_test_dir = File.dirname(__FILE__)
|
3
|
+
RAILS_ROOT = plugin_test_dir
|
3
4
|
|
4
5
|
require 'rubygems'
|
5
6
|
require 'test/unit'
|
6
7
|
require 'multi_rails_init'
|
7
|
-
require '
|
8
|
-
require 'action_controller'
|
9
|
-
require 'action_view'
|
10
|
-
require 'active_record/fixtures'
|
8
|
+
require 'test_help'
|
11
9
|
|
12
10
|
require plugin_test_dir + '/../init.rb'
|
13
11
|
|
12
|
+
TestCaseClass = ActiveSupport::TestCase rescue Test::Unit::TestCase
|
13
|
+
|
14
14
|
ActiveRecord::Base.logger = Logger.new(plugin_test_dir + "/debug.log")
|
15
15
|
|
16
16
|
ActiveRecord::Base.configurations = YAML::load(IO.read(plugin_test_dir + "/db/database.yml"))
|
@@ -21,10 +21,10 @@ load(File.join(plugin_test_dir, "db", "schema.rb"))
|
|
21
21
|
Dir["#{plugin_test_dir}/fixtures/*.rb"].each {|file| require file }
|
22
22
|
|
23
23
|
|
24
|
-
class
|
24
|
+
class TestCaseClass #:nodoc:
|
25
25
|
self.fixture_path = File.dirname(__FILE__) + "/fixtures/"
|
26
26
|
self.use_transactional_fixtures = true
|
27
27
|
self.use_instantiated_fixtures = false
|
28
28
|
|
29
29
|
fixtures :categories, :notes, :departments
|
30
|
-
end
|
30
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: collectiveidea-awesome_nested_set
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Brandon Keepers
|
@@ -10,7 +10,7 @@ autorequire:
|
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
12
|
|
13
|
-
date: 2009-
|
13
|
+
date: 2009-08-11 00:00:00 -07:00
|
14
14
|
default_executable:
|
15
15
|
dependencies:
|
16
16
|
- !ruby/object:Gem::Dependency
|
@@ -41,10 +41,9 @@ files:
|
|
41
41
|
- awesome_nested_set.gemspec
|
42
42
|
- init.rb
|
43
43
|
- lib/awesome_nested_set.rb
|
44
|
-
- lib/awesome_nested_set/compatability.rb
|
45
44
|
- lib/awesome_nested_set/helper.rb
|
46
|
-
- lib/awesome_nested_set/named_scope.rb
|
47
45
|
- rails/init.rb
|
46
|
+
- test/application.rb
|
48
47
|
- test/awesome_nested_set/helper_test.rb
|
49
48
|
- test/awesome_nested_set_test.rb
|
50
49
|
- test/db/database.yml
|
@@ -56,6 +55,7 @@ files:
|
|
56
55
|
- test/test_helper.rb
|
57
56
|
has_rdoc: false
|
58
57
|
homepage: http://github.com/collectiveidea/awesome_nested_set
|
58
|
+
licenses:
|
59
59
|
post_install_message:
|
60
60
|
rdoc_options:
|
61
61
|
- --main
|
@@ -79,7 +79,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
79
79
|
requirements: []
|
80
80
|
|
81
81
|
rubyforge_project:
|
82
|
-
rubygems_version: 1.
|
82
|
+
rubygems_version: 1.3.5
|
83
83
|
signing_key:
|
84
84
|
specification_version: 3
|
85
85
|
summary: An awesome nested set implementation for Active Record
|
@@ -88,6 +88,7 @@ test_files:
|
|
88
88
|
- test/fixtures/categories.yml
|
89
89
|
- test/fixtures/departments.yml
|
90
90
|
- test/fixtures/notes.yml
|
91
|
+
- test/application.rb
|
91
92
|
- test/awesome_nested_set/helper_test.rb
|
92
93
|
- test/awesome_nested_set_test.rb
|
93
94
|
- test/db/schema.rb
|
@@ -1,29 +0,0 @@
|
|
1
|
-
# Rails <2.x doesn't define #except
|
2
|
-
class Hash #:nodoc:
|
3
|
-
# Returns a new hash without the given keys.
|
4
|
-
def except(*keys)
|
5
|
-
clone.except!(*keys)
|
6
|
-
end unless method_defined?(:except)
|
7
|
-
|
8
|
-
# Replaces the hash without the given keys.
|
9
|
-
def except!(*keys)
|
10
|
-
keys.map! { |key| convert_key(key) } if respond_to?(:convert_key)
|
11
|
-
keys.each { |key| delete(key) }
|
12
|
-
self
|
13
|
-
end unless method_defined?(:except!)
|
14
|
-
end
|
15
|
-
|
16
|
-
# NamedScope is new to Rails 2.1
|
17
|
-
unless defined? ActiveRecord::NamedScope
|
18
|
-
require 'awesome_nested_set/named_scope'
|
19
|
-
ActiveRecord::Base.class_eval do
|
20
|
-
include CollectiveIdea::NamedScope
|
21
|
-
end
|
22
|
-
end
|
23
|
-
|
24
|
-
# Rails 1.2.x doesn't define #quoted_table_name
|
25
|
-
class ActiveRecord::Base #:nodoc:
|
26
|
-
def self.quoted_table_name
|
27
|
-
self.connection.quote_column_name(self.table_name)
|
28
|
-
end unless methods.include?('quoted_table_name')
|
29
|
-
end
|
@@ -1,140 +0,0 @@
|
|
1
|
-
# Taken from Rails 2.1
|
2
|
-
module CollectiveIdea #:nodoc:
|
3
|
-
module NamedScope #:nodoc:
|
4
|
-
# All subclasses of ActiveRecord::Base have two named_scopes:
|
5
|
-
# * <tt>all</tt>, which is similar to a <tt>find(:all)</tt> query, and
|
6
|
-
# * <tt>scoped</tt>, which allows for the creation of anonymous scopes, on the fly:
|
7
|
-
#
|
8
|
-
# Shirt.scoped(:conditions => {:color => 'red'}).scoped(:include => :washing_instructions)
|
9
|
-
#
|
10
|
-
# These anonymous scopes tend to be useful when procedurally generating complex queries, where passing
|
11
|
-
# intermediate values (scopes) around as first-class objects is convenient.
|
12
|
-
def self.included(base)
|
13
|
-
base.class_eval do
|
14
|
-
extend ClassMethods
|
15
|
-
named_scope :scoped, lambda { |scope| scope }
|
16
|
-
end
|
17
|
-
end
|
18
|
-
|
19
|
-
module ClassMethods #:nodoc:
|
20
|
-
def scopes
|
21
|
-
read_inheritable_attribute(:scopes) || write_inheritable_attribute(:scopes, {})
|
22
|
-
end
|
23
|
-
|
24
|
-
# Adds a class method for retrieving and querying objects. A scope represents a narrowing of a database query,
|
25
|
-
# such as <tt>:conditions => {:color => :red}, :select => 'shirts.*', :include => :washing_instructions</tt>.
|
26
|
-
#
|
27
|
-
# class Shirt < ActiveRecord::Base
|
28
|
-
# named_scope :red, :conditions => {:color => 'red'}
|
29
|
-
# named_scope :dry_clean_only, :joins => :washing_instructions, :conditions => ['washing_instructions.dry_clean_only = ?', true]
|
30
|
-
# end
|
31
|
-
#
|
32
|
-
# The above calls to <tt>named_scope</tt> define class methods <tt>Shirt.red</tt> and <tt>Shirt.dry_clean_only</tt>. <tt>Shirt.red</tt>,
|
33
|
-
# in effect, represents the query <tt>Shirt.find(:all, :conditions => {:color => 'red'})</tt>.
|
34
|
-
#
|
35
|
-
# Unlike Shirt.find(...), however, the object returned by <tt>Shirt.red</tt> is not an Array; it resembles the association object
|
36
|
-
# constructed by a <tt>has_many</tt> declaration. For instance, you can invoke <tt>Shirt.red.find(:first)</tt>, <tt>Shirt.red.count</tt>,
|
37
|
-
# <tt>Shirt.red.find(:all, :conditions => {:size => 'small'})</tt>. Also, just
|
38
|
-
# as with the association objects, name scopes acts like an Array, implementing Enumerable; <tt>Shirt.red.each(&block)</tt>,
|
39
|
-
# <tt>Shirt.red.first</tt>, and <tt>Shirt.red.inject(memo, &block)</tt> all behave as if Shirt.red really were an Array.
|
40
|
-
#
|
41
|
-
# These named scopes are composable. For instance, <tt>Shirt.red.dry_clean_only</tt> will produce all shirts that are both red and dry clean only.
|
42
|
-
# Nested finds and calculations also work with these compositions: <tt>Shirt.red.dry_clean_only.count</tt> returns the number of garments
|
43
|
-
# for which these criteria obtain. Similarly with <tt>Shirt.red.dry_clean_only.average(:thread_count)</tt>.
|
44
|
-
#
|
45
|
-
# All scopes are available as class methods on the ActiveRecord descendent upon which the scopes were defined. But they are also available to
|
46
|
-
# <tt>has_many</tt> associations. If,
|
47
|
-
#
|
48
|
-
# class Person < ActiveRecord::Base
|
49
|
-
# has_many :shirts
|
50
|
-
# end
|
51
|
-
#
|
52
|
-
# then <tt>elton.shirts.red.dry_clean_only</tt> will return all of Elton's red, dry clean
|
53
|
-
# only shirts.
|
54
|
-
#
|
55
|
-
# Named scopes can also be procedural.
|
56
|
-
#
|
57
|
-
# class Shirt < ActiveRecord::Base
|
58
|
-
# named_scope :colored, lambda { |color|
|
59
|
-
# { :conditions => { :color => color } }
|
60
|
-
# }
|
61
|
-
# end
|
62
|
-
#
|
63
|
-
# In this example, <tt>Shirt.colored('puce')</tt> finds all puce shirts.
|
64
|
-
#
|
65
|
-
# Named scopes can also have extensions, just as with <tt>has_many</tt> declarations:
|
66
|
-
#
|
67
|
-
# class Shirt < ActiveRecord::Base
|
68
|
-
# named_scope :red, :conditions => {:color => 'red'} do
|
69
|
-
# def dom_id
|
70
|
-
# 'red_shirts'
|
71
|
-
# end
|
72
|
-
# end
|
73
|
-
# end
|
74
|
-
#
|
75
|
-
#
|
76
|
-
# For testing complex named scopes, you can examine the scoping options using the
|
77
|
-
# <tt>proxy_options</tt> method on the proxy itself.
|
78
|
-
#
|
79
|
-
# class Shirt < ActiveRecord::Base
|
80
|
-
# named_scope :colored, lambda { |color|
|
81
|
-
# { :conditions => { :color => color } }
|
82
|
-
# }
|
83
|
-
# end
|
84
|
-
#
|
85
|
-
# expected_options = { :conditions => { :colored => 'red' } }
|
86
|
-
# assert_equal expected_options, Shirt.colored('red').proxy_options
|
87
|
-
def named_scope(name, options = {}, &block)
|
88
|
-
scopes[name] = lambda do |parent_scope, *args|
|
89
|
-
Scope.new(parent_scope, case options
|
90
|
-
when Hash
|
91
|
-
options
|
92
|
-
when Proc
|
93
|
-
options.call(*args)
|
94
|
-
end, &block)
|
95
|
-
end
|
96
|
-
(class << self; self end).instance_eval do
|
97
|
-
define_method name do |*args|
|
98
|
-
scopes[name].call(self, *args)
|
99
|
-
end
|
100
|
-
end
|
101
|
-
end
|
102
|
-
end
|
103
|
-
|
104
|
-
class Scope #:nodoc:
|
105
|
-
attr_reader :proxy_scope, :proxy_options
|
106
|
-
[].methods.each { |m| delegate m, :to => :proxy_found unless m =~ /(^__|^nil\?|^send|class|extend|find|count|sum|average|maximum|minimum|paginate)/ }
|
107
|
-
delegate :scopes, :with_scope, :to => :proxy_scope
|
108
|
-
|
109
|
-
def initialize(proxy_scope, options, &block)
|
110
|
-
[options[:extend]].flatten.each { |extension| extend extension } if options[:extend]
|
111
|
-
extend Module.new(&block) if block_given?
|
112
|
-
@proxy_scope, @proxy_options = proxy_scope, options.except(:extend)
|
113
|
-
end
|
114
|
-
|
115
|
-
def reload
|
116
|
-
load_found; self
|
117
|
-
end
|
118
|
-
|
119
|
-
protected
|
120
|
-
def proxy_found
|
121
|
-
@found || load_found
|
122
|
-
end
|
123
|
-
|
124
|
-
private
|
125
|
-
def method_missing(method, *args, &block)
|
126
|
-
if scopes.include?(method)
|
127
|
-
scopes[method].call(self, *args)
|
128
|
-
else
|
129
|
-
with_scope :find => proxy_options do
|
130
|
-
proxy_scope.send(method, *args, &block)
|
131
|
-
end
|
132
|
-
end
|
133
|
-
end
|
134
|
-
|
135
|
-
def load_found
|
136
|
-
@found = find(:all)
|
137
|
-
end
|
138
|
-
end
|
139
|
-
end
|
140
|
-
end
|