collectiveidea-awesome_nested_set 1.2.0 → 1.3.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|