metaskills-grouped_scope 0.5.1 → 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
data/README.rdoc CHANGED
@@ -5,7 +5,7 @@ GroupedScope aims to make two things easier in your ActiveRecord models. First,
5
5
  easy way to group objects, second, to allow the group to share associated object via existing
6
6
  has_many relationships. See installation and usage for more details.
7
7
 
8
- By the way, this plugin has been tested with rails 1.2.6, 2.0.4, and 2.1.1.
8
+ By the way, this plugin has been tested with rails 2.3.2, 2.2.2, and 2.1.1
9
9
 
10
10
 
11
11
  === Installation & Usage
data/Rakefile CHANGED
@@ -20,10 +20,10 @@ Rake::TestTask.new(:test) do |t|
20
20
  t.verbose = true
21
21
  end
22
22
 
23
- desc 'Test the GroupedScope plugin with Rails 2.1.1, 2.0.4 & 1.2.6 gems'
23
+ desc 'Test the GroupedScope plugin with Rails 2.3.2, 2.2.2, and 2.1.1 gems'
24
24
  task :test_rails do
25
25
  test = Rake::Task['test']
26
- versions = ['2.2.2','2.1.1','2.0.4','1.2.6']
26
+ versions = ['2.3.2','2.2.2','2.1.1']
27
27
  versions.each do |version|
28
28
  ENV['RAILS_VERSION'] = "#{version}"
29
29
  test.invoke
data/lib/grouped_scope.rb CHANGED
@@ -1,3 +1,4 @@
1
+ require 'active_record/version'
1
2
  require 'grouped_scope/errors'
2
3
  require 'grouped_scope/grouping'
3
4
  require 'grouped_scope/self_grouping'
@@ -9,7 +10,7 @@ require 'grouped_scope/core_ext'
9
10
 
10
11
  module GroupedScope
11
12
 
12
- VERSION = '0.5.1'
13
+ VERSION = '0.6.0'
13
14
 
14
15
  end
15
16
 
@@ -5,13 +5,21 @@ class ActiveRecord::Base
5
5
 
6
6
  private
7
7
 
8
- def attribute_condition_with_grouped_scope(argument)
9
- case argument
10
- when GroupedScope::SelfGroupping then "IN (?)"
11
- else attribute_condition_without_grouped_scope(argument)
8
+ def attribute_condition_with_grouped_scope(*args)
9
+ if ActiveRecord::VERSION::STRING >= '2.3.0'
10
+ quoted_column_name, argument = args
11
+ case argument
12
+ when GroupedScope::SelfGroupping then "#{quoted_column_name} IN (?)"
13
+ else attribute_condition_without_grouped_scope(quoted_column_name,argument)
14
+ end
15
+ else
16
+ argument = args.first
17
+ case argument
18
+ when GroupedScope::SelfGroupping then "IN (?)"
19
+ else attribute_condition_without_grouped_scope(argument)
20
+ end
12
21
  end
13
22
  end
14
-
15
23
  alias_method_chain :attribute_condition, :grouped_scope
16
24
 
17
25
  end
@@ -9,12 +9,10 @@ module GroupedScope
9
9
 
10
10
  def construct_sql_with_group_scope
11
11
  if @reflection.options[:grouped_scope]
12
- # CHANGED [Rails 1.2.6] Account for quoted_table_name.
13
- table_name = @reflection.respond_to?(:quoted_table_name) ? @reflection.quoted_table_name : @reflection.klass.table_name
14
12
  if @reflection.options[:as]
15
13
  # TODO: Need to add case for polymorphic :as option.
16
14
  else
17
- @finder_sql = "#{table_name}.#{@reflection.primary_key_name} IN (#{@owner.group.quoted_ids})"
15
+ @finder_sql = "#{@reflection.quoted_table_name}.#{@reflection.primary_key_name} IN (#{@owner.group.quoted_ids})"
18
16
  @finder_sql << " AND (#{conditions})" if conditions
19
17
  end
20
18
  @counter_sql = @finder_sql
@@ -40,8 +40,6 @@ class GroupedScope::AssociationReflectionTest < GroupedScope::TestCase
40
40
  should 'delegate instance methods to #ungrouped_reflection' do
41
41
  methods = [:class_name,:klass,:table_name,:primary_key_name,:active_record,
42
42
  :association_foreign_key,:counter_cache_column,:source_reflection]
43
- # CHANGED [Rails 1.2.6] Account for quoted_table_name.
44
- methods << :quoted_table_name if @ungrouped_reflection.respond_to?(:quoted_table_name)
45
43
  methods.each do |m|
46
44
  assert_equal @ungrouped_reflection.send(m), @grouped_reflection.send(m),
47
45
  "The method #{m.inspect} does not appear to be proxied to the ungrouped reflection."
@@ -54,17 +52,11 @@ class GroupedScope::AssociationReflectionTest < GroupedScope::TestCase
54
52
  end
55
53
 
56
54
  should 'derive class name to same as ungrouped reflection' do
57
- # CHANGED [Rails 1.2.6] Account for quoted_table_name.
58
- if @ungrouped_reflection.respond_to?(:derive_class_name)
59
- assert_equal @ungrouped_reflection.send(:derive_class_name), @grouped_reflection.send(:derive_class_name)
60
- end
55
+ assert_equal @ungrouped_reflection.send(:derive_class_name), @grouped_reflection.send(:derive_class_name)
61
56
  end
62
57
 
63
58
  should 'derive primary key name to same as ungrouped reflection' do
64
- # CHANGED [Rails 1.2.6] Account for quoted_table_name.
65
- if @ungrouped_reflection.respond_to?(:derive_primary_key_name)
66
- assert_equal @ungrouped_reflection.send(:derive_primary_key_name), @grouped_reflection.send(:derive_primary_key_name)
67
- end
59
+ assert_equal @ungrouped_reflection.send(:derive_primary_key_name), @grouped_reflection.send(:derive_primary_key_name)
68
60
  end
69
61
 
70
62
  should 'honor explicit legacy reports association options like class_name and foreign_key' do
data/test/lib/boot.rb CHANGED
@@ -28,5 +28,4 @@ require 'active_support'
28
28
  gem 'mislav-will_paginate', '2.3.4'
29
29
  require 'will_paginate'
30
30
  WillPaginate.enable_activerecord
31
- require 'named_scope'
32
31
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: metaskills-grouped_scope
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.1
4
+ version: 0.6.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ken Collins
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-01-07 00:00:00 -08:00
12
+ date: 2009-05-06 00:00:00 -07:00
13
13
  default_executable:
14
14
  dependencies: []
15
15
 
@@ -75,10 +75,4 @@ test_files:
75
75
  - test/grouped_scope/self_grouping_test.rb
76
76
  - test/helper.rb
77
77
  - test/lib/boot.rb
78
- - test/lib/core_ext.rb
79
- - test/lib/named_scope.rb
80
- - test/lib/named_scope/core_ext.rb
81
- - test/lib/named_scope/named_scope.rb
82
- - test/lib/named_scope/named_scope_patch_1.2.rb
83
- - test/lib/named_scope/named_scope_patch_2.0.rb
84
78
  - test/lib/test_case.rb
data/test/lib/core_ext.rb DELETED
@@ -1,20 +0,0 @@
1
-
2
- unless Hash.instance_methods.include? 'except'
3
-
4
- Hash.class_eval do
5
-
6
- # Returns a new hash without the given keys.
7
- def except(*keys)
8
- rejected = Set.new(respond_to?(:convert_key) ? keys.map { |key| convert_key(key) } : keys)
9
- reject { |key,| rejected.include?(key) }
10
- end
11
-
12
- # Replaces the hash without only the given keys.
13
- def except!(*keys)
14
- replace(except(*keys))
15
- end
16
-
17
- end
18
-
19
- end
20
-
@@ -1,7 +0,0 @@
1
- unless defined? ActiveRecord::NamedScope
2
- require "named_scope/core_ext"
3
- require "named_scope/named_scope"
4
- require "named_scope/named_scope_patch_#{ActiveRecord::Base.respond_to?(:find_first) ? '1.2' : '2.0'}"
5
- ActiveRecord::Base.send :include, ActiveRecord::NamedScope
6
- end
7
-
@@ -1,82 +0,0 @@
1
-
2
- unless Hash.instance_methods.include? 'except'
3
- Hash.class_eval do
4
-
5
- # Returns a new hash without the given keys.
6
- def except(*keys)
7
- rejected = Set.new(respond_to?(:convert_key) ? keys.map { |key| convert_key(key) } : keys)
8
- reject { |key,| rejected.include?(key) }
9
- end
10
-
11
- # Replaces the hash without only the given keys.
12
- def except!(*keys)
13
- replace(except(*keys))
14
- end
15
-
16
- end
17
- end
18
-
19
- class ActiveRecord::Base
20
- class << self
21
-
22
- def first(*args)
23
- find(:first, *args)
24
- end
25
-
26
- def last(*args)
27
- find(:last, *args)
28
- end
29
-
30
- def all(*args)
31
- find(:all, *args)
32
- end
33
-
34
- private
35
-
36
- def find_last(options)
37
- order = options[:order]
38
- if order
39
- order = reverse_sql_order(order)
40
- elsif !scoped?(:find, :order)
41
- order = "#{table_name}.#{primary_key} DESC"
42
- end
43
- if scoped?(:find, :order)
44
- scoped_order = reverse_sql_order(scope(:find, :order))
45
- scoped_methods.select { |s| s[:find].update(:order => scoped_order) }
46
- end
47
- find_initial(options.merge({ :order => order }))
48
- end
49
-
50
- def reverse_sql_order(order_query)
51
- reversed_query = order_query.split(/,/).each { |s|
52
- if s.match(/\s(asc|ASC)$/)
53
- s.gsub!(/\s(asc|ASC)$/, ' DESC')
54
- elsif s.match(/\s(desc|DESC)$/)
55
- s.gsub!(/\s(desc|DESC)$/, ' ASC')
56
- elsif !s.match(/\s(asc|ASC|desc|DESC)$/)
57
- s.concat(' DESC')
58
- end
59
- }.join(',')
60
- end
61
-
62
- end
63
- end
64
-
65
- ActiveRecord::Associations::AssociationCollection.class_eval do
66
-
67
- def last(*args)
68
- if fetch_first_or_last_using_find? args
69
- find(:last, *args)
70
- else
71
- load_target unless loaded?
72
- @target.last(*args)
73
- end
74
- end
75
-
76
- private
77
-
78
- def fetch_first_or_last_using_find?(args)
79
- args.first.kind_of?(Hash) || !(loaded? || @owner.new_record? || @reflection.options[:finder_sql] || !@target.blank? || args.first.kind_of?(Integer))
80
- end
81
-
82
- end
@@ -1,168 +0,0 @@
1
- module ActiveRecord
2
- module NamedScope
3
- # All subclasses of ActiveRecord::Base have two named_scopes:
4
- # * <tt>all</tt>, which is similar to a <tt>find(:all)</tt> query, and
5
- # * <tt>scoped</tt>, which allows for the creation of anonymous scopes, on the fly: <tt>Shirt.scoped(:conditions => {:color => 'red'}).scoped(:include => :washing_instructions)</tt>
6
- #
7
- # These anonymous scopes tend to be useful when procedurally generating complex queries, where passing
8
- # intermediate values (scopes) around as first-class objects is convenient.
9
- def self.included(base)
10
- base.class_eval do
11
- extend ClassMethods
12
- named_scope :scoped, lambda { |scope| scope }
13
- end
14
- end
15
-
16
- module ClassMethods
17
- def scopes
18
- read_inheritable_attribute(:scopes) || write_inheritable_attribute(:scopes, {})
19
- end
20
-
21
- # Adds a class method for retrieving and querying objects. A scope represents a narrowing of a database query,
22
- # such as <tt>:conditions => {:color => :red}, :select => 'shirts.*', :include => :washing_instructions</tt>.
23
- #
24
- # class Shirt < ActiveRecord::Base
25
- # named_scope :red, :conditions => {:color => 'red'}
26
- # named_scope :dry_clean_only, :joins => :washing_instructions, :conditions => ['washing_instructions.dry_clean_only = ?', true]
27
- # end
28
- #
29
- # 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>,
30
- # in effect, represents the query <tt>Shirt.find(:all, :conditions => {:color => 'red'})</tt>.
31
- #
32
- # Unlike Shirt.find(...), however, the object returned by <tt>Shirt.red</tt> is not an Array; it resembles the association object
33
- # constructed by a <tt>has_many</tt> declaration. For instance, you can invoke <tt>Shirt.red.find(:first)</tt>, <tt>Shirt.red.count</tt>,
34
- # <tt>Shirt.red.find(:all, :conditions => {:size => 'small'})</tt>. Also, just
35
- # as with the association objects, name scopes acts like an Array, implementing Enumerable; <tt>Shirt.red.each(&block)</tt>,
36
- # <tt>Shirt.red.first</tt>, and <tt>Shirt.red.inject(memo, &block)</tt> all behave as if Shirt.red really were an Array.
37
- #
38
- # 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.
39
- # Nested finds and calculations also work with these compositions: <tt>Shirt.red.dry_clean_only.count</tt> returns the number of garments
40
- # for which these criteria obtain. Similarly with <tt>Shirt.red.dry_clean_only.average(:thread_count)</tt>.
41
- #
42
- # All scopes are available as class methods on the ActiveRecord::Base descendent upon which the scopes were defined. But they are also available to
43
- # <tt>has_many</tt> associations. If,
44
- #
45
- # class Person < ActiveRecord::Base
46
- # has_many :shirts
47
- # end
48
- #
49
- # then <tt>elton.shirts.red.dry_clean_only</tt> will return all of Elton's red, dry clean
50
- # only shirts.
51
- #
52
- # Named scopes can also be procedural.
53
- #
54
- # class Shirt < ActiveRecord::Base
55
- # named_scope :colored, lambda { |color|
56
- # { :conditions => { :color => color } }
57
- # }
58
- # end
59
- #
60
- # In this example, <tt>Shirt.colored('puce')</tt> finds all puce shirts.
61
- #
62
- # Named scopes can also have extensions, just as with <tt>has_many</tt> declarations:
63
- #
64
- # class Shirt < ActiveRecord::Base
65
- # named_scope :red, :conditions => {:color => 'red'} do
66
- # def dom_id
67
- # 'red_shirts'
68
- # end
69
- # end
70
- # end
71
- #
72
- #
73
- # For testing complex named scopes, you can examine the scoping options using the
74
- # <tt>proxy_options</tt> method on the proxy itself.
75
- #
76
- # class Shirt < ActiveRecord::Base
77
- # named_scope :colored, lambda { |color|
78
- # { :conditions => { :color => color } }
79
- # }
80
- # end
81
- #
82
- # expected_options = { :conditions => { :colored => 'red' } }
83
- # assert_equal expected_options, Shirt.colored('red').proxy_options
84
- def named_scope(name, options = {}, &block)
85
- name = name.to_sym
86
- scopes[name] = lambda do |parent_scope, *args|
87
- Scope.new(parent_scope, case options
88
- when Hash
89
- options
90
- when Proc
91
- options.call(*args)
92
- end, &block)
93
- end
94
- (class << self; self end).instance_eval do
95
- define_method name do |*args|
96
- scopes[name].call(self, *args)
97
- end
98
- end
99
- end
100
- end
101
-
102
- class Scope
103
- attr_reader :proxy_scope, :proxy_options
104
-
105
- [].methods.each do |m|
106
- unless m =~ /(^__|^nil\?|^send|^object_id$|class|extend|^find$|count|sum|average|maximum|minimum|paginate|first|last|empty\?|respond_to\?)/
107
- delegate m, :to => :proxy_found
108
- end
109
- end
110
-
111
- delegate :scopes, :with_scope, :to => :proxy_scope
112
-
113
- def initialize(proxy_scope, options, &block)
114
- [options[:extend]].flatten.each { |extension| extend extension } if options[:extend]
115
- extend Module.new(&block) if block_given?
116
- @proxy_scope, @proxy_options = proxy_scope, options.except(:extend)
117
- end
118
-
119
- def reload
120
- load_found; self
121
- end
122
-
123
- def first(*args)
124
- if args.first.kind_of?(Integer) || (@found && !args.first.kind_of?(Hash))
125
- proxy_found.first(*args)
126
- else
127
- find(:first, *args)
128
- end
129
- end
130
-
131
- def last(*args)
132
- if args.first.kind_of?(Integer) || (@found && !args.first.kind_of?(Hash))
133
- proxy_found.last(*args)
134
- else
135
- find(:last, *args)
136
- end
137
- end
138
-
139
- def empty?
140
- @found ? @found.empty? : count.zero?
141
- end
142
-
143
- def respond_to?(method, include_private = false)
144
- super || @proxy_scope.respond_to?(method, include_private)
145
- end
146
-
147
- protected
148
- def proxy_found
149
- @found || load_found
150
- end
151
-
152
- private
153
- def method_missing(method, *args, &block)
154
- if scopes.include?(method)
155
- scopes[method].call(self, *args)
156
- else
157
- with_scope :find => proxy_options do
158
- proxy_scope.send(method, *args, &block)
159
- end
160
- end
161
- end
162
-
163
- def load_found
164
- @found = find(:all)
165
- end
166
- end
167
- end
168
- end
@@ -1,85 +0,0 @@
1
-
2
- ActiveRecord::Associations::AssociationProxy.class_eval do
3
- protected
4
- def with_scope(*args, &block)
5
- @reflection.klass.send :with_scope, *args, &block
6
- end
7
- end
8
-
9
- class ActiveRecord::Base
10
- class << self
11
- def find(*args)
12
- options = extract_options_from_args!(args)
13
- validate_find_options(options)
14
- set_readonly_option!(options)
15
- case args.first
16
- when :first then find_initial(options)
17
- when :last then find_last(options)
18
- when :all then find_every(options)
19
- else find_from_ids(args, options)
20
- end
21
- end
22
- private
23
- def attribute_condition_with_named_scope(argument)
24
- case argument
25
- when ActiveRecord::Associations::AssociationCollection, ActiveRecord::NamedScope::Scope then "IN (?)"
26
- else attribute_condition_without_named_scope(argument)
27
- end
28
- end
29
- alias_method_chain :attribute_condition, :named_scope
30
- end
31
- end
32
-
33
- ActiveRecord::Associations::HasManyAssociation.class_eval do
34
- protected
35
- def method_missing(method, *args, &block)
36
- if @target.respond_to?(method) || (!@reflection.klass.respond_to?(method) && Class.respond_to?(method))
37
- super
38
- elsif @reflection.klass.scopes.include?(method)
39
- @reflection.klass.scopes[method].call(self, *args)
40
- else
41
- create_scoping = {}
42
- set_belongs_to_association_for(create_scoping)
43
-
44
- @reflection.klass.with_scope(
45
- :create => create_scoping,
46
- :find => {
47
- :conditions => @finder_sql,
48
- :joins => @join_sql,
49
- :readonly => false
50
- }
51
- ) do
52
- @reflection.klass.send(method, *args, &block)
53
- end
54
- end
55
- end
56
- end
57
-
58
- ActiveRecord::Associations::HasManyThroughAssociation.class_eval do
59
- protected
60
- def method_missing(method, *args, &block)
61
- if @target.respond_to?(method) || (!@reflection.klass.respond_to?(method) && Class.respond_to?(method))
62
- super
63
- elsif @reflection.klass.scopes.include?(method)
64
- @reflection.klass.scopes[method].call(self, *args)
65
- else
66
- @reflection.klass.with_scope(construct_scope) { @reflection.klass.send(method, *args, &block) }
67
- end
68
- end
69
- end
70
-
71
- ActiveRecord::Associations::HasAndBelongsToManyAssociation.class_eval do
72
- protected
73
- def method_missing(method, *args, &block)
74
- if @target.respond_to?(method) || (!@reflection.klass.respond_to?(method) && Class.respond_to?(method))
75
- super
76
- elsif @reflection.klass.scopes.include?(method)
77
- @reflection.klass.scopes[method].call(self, *args)
78
- else
79
- @reflection.klass.with_scope(:find => { :conditions => @finder_sql, :joins => @join_sql, :readonly => false }) do
80
- @reflection.klass.send(method, *args, &block)
81
- end
82
- end
83
- end
84
- end
85
-
@@ -1,55 +0,0 @@
1
-
2
- ActiveRecord::Associations::AssociationProxy.class_eval do
3
- protected
4
- def with_scope(*args, &block)
5
- @reflection.klass.send :with_scope, *args, &block
6
- end
7
- end
8
-
9
- class ActiveRecord::Base
10
- class << self
11
- def find(*args)
12
- options = args.extract_options!
13
- validate_find_options(options)
14
- set_readonly_option!(options)
15
- case args.first
16
- when :first then find_initial(options)
17
- when :last then find_last(options)
18
- when :all then find_every(options)
19
- else find_from_ids(args, options)
20
- end
21
- end
22
- private
23
- def attribute_condition_with_named_scope(argument)
24
- case argument
25
- when ActiveRecord::NamedScope::Scope then "IN (?)"
26
- else attribute_condition_without_named_scope(argument)
27
- end
28
- end
29
- alias_method_chain :attribute_condition, :named_scope
30
- end
31
- end
32
-
33
- ActiveRecord::Associations::AssociationCollection.class_eval do
34
- protected
35
- def method_missing(method, *args)
36
- if @target.respond_to?(method) || (!@reflection.klass.respond_to?(method) && Class.respond_to?(method))
37
- if block_given?
38
- super { |*block_args| yield(*block_args) }
39
- else
40
- super
41
- end
42
- elsif @reflection.klass.scopes.include?(method)
43
- @reflection.klass.scopes[method].call(self, *args)
44
- else
45
- with_scope(construct_scope) do
46
- if block_given?
47
- @reflection.klass.send(method, *args) { |*block_args| yield(*block_args) }
48
- else
49
- @reflection.klass.send(method, *args)
50
- end
51
- end
52
- end
53
- end
54
- end
55
-