dweinand-will_paginate 2.3.4 → 2.3.7

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.
@@ -1,3 +1,13 @@
1
+ == 2.3.6, released 2008-10-26
2
+
3
+ * Rails 2.2 fix: stop using `extract_attribute_names_from_match` inernal AR method, it no longer exists
4
+
5
+ == 2.3.5, released 2008-10-07
6
+
7
+ * update the backported named_scope implementation for Rails versions older than 2.1
8
+ * break out of scope of paginated_each() yielded block when used on named scopes
9
+ * fix paginate(:from)
10
+
1
11
  == 2.3.4, released 2008-09-16
2
12
 
3
13
  * Removed gem dependency to Active Support (causes trouble with vendored rails).
@@ -80,11 +80,7 @@ module WillPaginate
80
80
 
81
81
  def self.warn(message, callstack = caller)
82
82
  message = 'WillPaginate: ' + message.strip.gsub(/\s+/, ' ')
83
- behavior.call(message, callstack) if behavior && !silenced?
84
- end
85
-
86
- def self.silenced?
87
- ActiveSupport::Deprecation.silenced?
83
+ ActiveSupport::Deprecation.warn(message, callstack)
88
84
  end
89
85
  end
90
86
  end
@@ -83,7 +83,7 @@ module WillPaginate
83
83
  #
84
84
  # The Array#paginate API has since then changed, but this still serves as a
85
85
  # fine example of WillPaginate::Collection usage.
86
- def self.create(page, per_page, total = nil, &block)
86
+ def self.create(page, per_page, total = nil)
87
87
  pager = new(page, per_page, total)
88
88
  yield pager
89
89
  pager
@@ -61,7 +61,7 @@ module WillPaginate
61
61
  #
62
62
  # All other options (+conditions+, +order+, ...) are forwarded to +find+
63
63
  # and +count+ calls.
64
- def paginate(*args, &block)
64
+ def paginate(*args)
65
65
  options = args.pop
66
66
  page, per_page, total_entries = wp_parse_options(options)
67
67
  finder = (options[:finder] || 'find').to_s
@@ -79,7 +79,7 @@ module WillPaginate
79
79
 
80
80
  args << find_options
81
81
  # @options_from_last_find = nil
82
- pager.replace send(finder, *args, &block)
82
+ pager.replace(send(finder, *args) { |*a| yield(*a) if block_given? })
83
83
 
84
84
  # magic counting for user convenience:
85
85
  pager.total_entries = wp_count(count_options, args, finder) unless pager.total_entries
@@ -96,7 +96,7 @@ module WillPaginate
96
96
  #
97
97
  # See {Faking Cursors in ActiveRecord}[http://weblog.jamisbuck.org/2007/4/6/faking-cursors-in-activerecord]
98
98
  # where Jamis Buck describes this and a more efficient way for MySQL.
99
- def paginated_each(options = {}, &block)
99
+ def paginated_each(options = {})
100
100
  options = { :order => 'id', :page => 1 }.merge options
101
101
  options[:page] = options[:page].to_i
102
102
  options[:total_entries] = 0 # skip the individual count queries
@@ -104,7 +104,10 @@ module WillPaginate
104
104
 
105
105
  begin
106
106
  collection = paginate(options)
107
- total += collection.each(&block).size
107
+ with_exclusive_scope(:find => {}) do
108
+ # using exclusive scope so that the block is yielded in scope-free context
109
+ total += collection.each { |item| yield item }.size
110
+ end
108
111
  options[:page] += 1
109
112
  end until collection.size < collection.per_page
110
113
 
@@ -158,10 +161,14 @@ module WillPaginate
158
161
 
159
162
  protected
160
163
 
161
- def method_missing_with_paginate(method, *args, &block) #:nodoc:
164
+ def method_missing_with_paginate(method, *args) #:nodoc:
162
165
  # did somebody tried to paginate? if not, let them be
163
166
  unless method.to_s.index('paginate') == 0
164
- return method_missing_without_paginate(method, *args, &block)
167
+ if block_given?
168
+ return method_missing_without_paginate(method, *args) { |*a| yield(*a) }
169
+ else
170
+ return method_missing_without_paginate(method, *args)
171
+ end
165
172
  end
166
173
 
167
174
  # paginate finders are really just find_* with limit and offset
@@ -174,13 +181,14 @@ module WillPaginate
174
181
  options[:finder] = finder
175
182
  args << options
176
183
 
177
- paginate(*args, &block)
184
+ paginate(*args) { |*a| yield(*a) if block_given? }
178
185
  end
179
186
 
180
187
  # Does the not-so-trivial job of finding out the total number of entries
181
188
  # in the database. It relies on the ActiveRecord +count+ method.
182
189
  def wp_count(options, args, finder)
183
190
  excludees = [:count, :order, :limit, :offset, :readonly]
191
+ excludees << :from unless ActiveRecord::Calculations::CALCULATIONS_OPTIONS.include?(:from)
184
192
 
185
193
  # we may be in a model or an association proxy
186
194
  klass = (@owner and @reflection) ? @reflection.klass : self
@@ -218,9 +226,9 @@ module WillPaginate
218
226
  # scope_out adds a 'with_finder' method which acts like with_scope, if it's present
219
227
  # then execute the count with the scoping provided by the with_finder
220
228
  send(scoper, &counter)
221
- elsif match = /^find_(all_by|by)_([_a-zA-Z]\w*)$/.match(finder)
229
+ elsif finder =~ /^find_(all_by|by)_([_a-zA-Z]\w*)$/
222
230
  # extract conditions from calls like "paginate_by_foo_and_bar"
223
- attribute_names = extract_attribute_names_from_match(match)
231
+ attribute_names = $2.split('_and_')
224
232
  conditions = construct_attributes_from_arguments(attribute_names, args)
225
233
  with_scope(:find => { :conditions => conditions }, &counter)
226
234
  else
@@ -1,27 +1,22 @@
1
- ## stolen from: http://dev.rubyonrails.org/browser/trunk/activerecord/lib/active_record/named_scope.rb?rev=9084
2
-
3
1
  module WillPaginate
4
2
  # This is a feature backported from Rails 2.1 because of its usefullness not only with will_paginate,
5
3
  # but in other aspects when managing complex conditions that you want to be reusable.
6
4
  module NamedScope
7
5
  # All subclasses of ActiveRecord::Base have two named_scopes:
8
6
  # * <tt>all</tt>, which is similar to a <tt>find(:all)</tt> query, and
9
- # * <tt>scoped</tt>, which allows for the creation of anonymous scopes, on the fly:
10
- #
11
- # Shirt.scoped(:conditions => {:color => 'red'}).scoped(:include => :washing_instructions)
7
+ # * <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>
12
8
  #
13
9
  # These anonymous scopes tend to be useful when procedurally generating complex queries, where passing
14
10
  # intermediate values (scopes) around as first-class objects is convenient.
15
11
  def self.included(base)
16
12
  base.class_eval do
17
13
  extend ClassMethods
18
- named_scope :all
19
14
  named_scope :scoped, lambda { |scope| scope }
20
15
  end
21
16
  end
22
17
 
23
18
  module ClassMethods
24
- def scopes #:nodoc:
19
+ def scopes
25
20
  read_inheritable_attribute(:scopes) || write_inheritable_attribute(:scopes, {})
26
21
  end
27
22
 
@@ -46,7 +41,7 @@ module WillPaginate
46
41
  # Nested finds and calculations also work with these compositions: <tt>Shirt.red.dry_clean_only.count</tt> returns the number of garments
47
42
  # for which these criteria obtain. Similarly with <tt>Shirt.red.dry_clean_only.average(:thread_count)</tt>.
48
43
  #
49
- # All scopes are available as class methods on the ActiveRecord descendent upon which the scopes were defined. But they are also available to
44
+ # All scopes are available as class methods on the ActiveRecord::Base descendent upon which the scopes were defined. But they are also available to
50
45
  # <tt>has_many</tt> associations. If,
51
46
  #
52
47
  # class Person < ActiveRecord::Base
@@ -76,14 +71,27 @@ module WillPaginate
76
71
  # end
77
72
  # end
78
73
  #
79
- def named_scope(name, options = {}, &block)
74
+ #
75
+ # For testing complex named scopes, you can examine the scoping options using the
76
+ # <tt>proxy_options</tt> method on the proxy itself.
77
+ #
78
+ # class Shirt < ActiveRecord::Base
79
+ # named_scope :colored, lambda { |color|
80
+ # { :conditions => { :color => color } }
81
+ # }
82
+ # end
83
+ #
84
+ # expected_options = { :conditions => { :colored => 'red' } }
85
+ # assert_equal expected_options, Shirt.colored('red').proxy_options
86
+ def named_scope(name, options = {})
87
+ name = name.to_sym
80
88
  scopes[name] = lambda do |parent_scope, *args|
81
89
  Scope.new(parent_scope, case options
82
90
  when Hash
83
91
  options
84
92
  when Proc
85
93
  options.call(*args)
86
- end, &block)
94
+ end) { |*a| yield(*a) if block_given? }
87
95
  end
88
96
  (class << self; self end).instance_eval do
89
97
  define_method name do |*args|
@@ -93,14 +101,20 @@ module WillPaginate
93
101
  end
94
102
  end
95
103
 
96
- class Scope #:nodoc:
104
+ class Scope
97
105
  attr_reader :proxy_scope, :proxy_options
98
- [].methods.each { |m| delegate m, :to => :proxy_found unless m =~ /(^__|^nil\?|^send|class|extend|find|count|sum|average|maximum|minimum|paginate)/ }
106
+
107
+ [].methods.each do |m|
108
+ unless m =~ /(^__|^nil\?|^send|^object_id$|class|extend|^find$|count|sum|average|maximum|minimum|paginate|first|last|empty\?|respond_to\?)/
109
+ delegate m, :to => :proxy_found
110
+ end
111
+ end
112
+
99
113
  delegate :scopes, :with_scope, :to => :proxy_scope
100
114
 
101
- def initialize(proxy_scope, options, &block)
115
+ def initialize(proxy_scope, options)
102
116
  [options[:extend]].flatten.each { |extension| extend extension } if options[:extend]
103
- extend Module.new(&block) if block_given?
117
+ extend Module.new { |*args| yield(*args) } if block_given?
104
118
  @proxy_scope, @proxy_options = proxy_scope, options.except(:extend)
105
119
  end
106
120
 
@@ -108,18 +122,42 @@ module WillPaginate
108
122
  load_found; self
109
123
  end
110
124
 
125
+ def first(*args)
126
+ if args.first.kind_of?(Integer) || (@found && !args.first.kind_of?(Hash))
127
+ proxy_found.first(*args)
128
+ else
129
+ find(:first, *args)
130
+ end
131
+ end
132
+
133
+ def last(*args)
134
+ if args.first.kind_of?(Integer) || (@found && !args.first.kind_of?(Hash))
135
+ proxy_found.last(*args)
136
+ else
137
+ find(:last, *args)
138
+ end
139
+ end
140
+
141
+ def empty?
142
+ @found ? @found.empty? : count.zero?
143
+ end
144
+
145
+ def respond_to?(method, include_private = false)
146
+ super || @proxy_scope.respond_to?(method, include_private)
147
+ end
148
+
111
149
  protected
112
150
  def proxy_found
113
151
  @found || load_found
114
152
  end
115
153
 
116
154
  private
117
- def method_missing(method, *args, &block)
155
+ def method_missing(method, *args)
118
156
  if scopes.include?(method)
119
157
  scopes[method].call(self, *args)
120
158
  else
121
159
  with_scope :find => proxy_options do
122
- proxy_scope.send(method, *args, &block)
160
+ proxy_scope.send(method, *args) { |*a| yield(*a) if block_given? }
123
161
  end
124
162
  end
125
163
  end
@@ -1,9 +1,7 @@
1
- ## based on http://dev.rubyonrails.org/changeset/9084
2
-
3
1
  ActiveRecord::Associations::AssociationProxy.class_eval do
4
2
  protected
5
- def with_scope(*args, &block)
6
- @reflection.klass.send :with_scope, *args, &block
3
+ def with_scope(*args)
4
+ @reflection.klass.send(:with_scope, *args) { |*a| yield(*a) if block_given? }
7
5
  end
8
6
  end
9
7
 
@@ -12,11 +10,11 @@ end
12
10
  klass.class_eval do
13
11
  protected
14
12
  alias :method_missing_without_scopes :method_missing_without_paginate
15
- def method_missing_without_paginate(method, *args, &block)
13
+ def method_missing_without_paginate(method, *args)
16
14
  if @reflection.klass.scopes.include?(method)
17
- @reflection.klass.scopes[method].call(self, *args, &block)
15
+ @reflection.klass.scopes[method].call(self, *args) { |*a| yield(*a) if block_given? }
18
16
  else
19
- method_missing_without_scopes(method, *args, &block)
17
+ method_missing_without_scopes(method, *args) { |*a| yield(*a) if block_given? }
20
18
  end
21
19
  end
22
20
  end
@@ -25,14 +23,14 @@ end
25
23
  # Rails 1.2.6
26
24
  ActiveRecord::Associations::HasAndBelongsToManyAssociation.class_eval do
27
25
  protected
28
- def method_missing(method, *args, &block)
26
+ def method_missing(method, *args)
29
27
  if @target.respond_to?(method) || (!@reflection.klass.respond_to?(method) && Class.respond_to?(method))
30
28
  super
31
29
  elsif @reflection.klass.scopes.include?(method)
32
30
  @reflection.klass.scopes[method].call(self, *args)
33
31
  else
34
32
  @reflection.klass.with_scope(:find => { :conditions => @finder_sql, :joins => @join_sql, :readonly => false }) do
35
- @reflection.klass.send(method, *args, &block)
33
+ @reflection.klass.send(method, *args) { |*a| yield(*a) if block_given? }
36
34
  end
37
35
  end
38
36
  end
@@ -2,7 +2,7 @@ module WillPaginate
2
2
  module VERSION
3
3
  MAJOR = 2
4
4
  MINOR = 3
5
- TINY = 3
5
+ TINY = 5
6
6
 
7
7
  STRING = [MAJOR, MINOR, TINY].join('.')
8
8
  end
@@ -99,7 +99,7 @@ module WillPaginate
99
99
 
100
100
  options = options.symbolize_keys.reverse_merge WillPaginate::ViewHelpers.pagination_options
101
101
  if options[:prev_label]
102
- WillPaginate::Deprecation::warn(":prev_label view parameter is now :previous_label; the old name has been deprecated.")
102
+ WillPaginate::Deprecation::warn(":prev_label view parameter is now :previous_label; the old name has been deprecated", caller)
103
103
  options[:previous_label] = options.delete(:prev_label)
104
104
  end
105
105
 
@@ -141,8 +141,15 @@ module WillPaginate
141
141
  # blocks of pagination links sharing the same ID (which is invalid HTML).
142
142
  def paginated_section(*args, &block)
143
143
  pagination = will_paginate(*args).to_s
144
- content = pagination + capture(&block) + pagination
145
- concat content, block.binding
144
+
145
+ unless ActionView::Base.respond_to? :erb_variable
146
+ concat pagination
147
+ yield
148
+ concat pagination
149
+ else
150
+ content = pagination + capture(&block) + pagination
151
+ concat(content, block.binding)
152
+ end
146
153
  end
147
154
 
148
155
  # Renders a helpful message with numbers of displayed vs. total entries.
@@ -178,12 +185,11 @@ module WillPaginate
178
185
 
179
186
  def self.total_pages_for_collection(collection) #:nodoc:
180
187
  if collection.respond_to?('page_count') and !collection.respond_to?('total_pages')
181
- WillPaginate::Deprecation.warn <<-MSG
188
+ WillPaginate::Deprecation.warn %{
182
189
  You are using a paginated collection of class #{collection.class.name}
183
190
  which conforms to the old API of WillPaginate::Collection by using
184
191
  `page_count`, while the current method name is `total_pages`. Please
185
- upgrade yours or 3rd-party code that provides the paginated collection.
186
- MSG
192
+ upgrade yours or 3rd-party code that provides the paginated collection}, caller
187
193
  class << collection
188
194
  def total_pages; page_count; end
189
195
  end
@@ -2,6 +2,9 @@ require 'helper'
2
2
  require 'will_paginate/array'
3
3
 
4
4
  class ArrayPaginationTest < Test::Unit::TestCase
5
+
6
+ def setup ; end
7
+
5
8
  def test_simple
6
9
  collection = ('a'..'e').to_a
7
10
 
@@ -17,6 +17,6 @@ mysql:
17
17
  postgres:
18
18
  adapter: postgresql
19
19
  username: mislav
20
- password: mislav
20
+ password:
21
21
  database: will_paginate_unittest
22
22
  min_messages: warning
@@ -261,6 +261,12 @@ class FinderTest < ActiveRecordTestCase
261
261
  assert_equal 1, entries.total_entries, 'only one topic should be found'
262
262
  end
263
263
  end
264
+
265
+ def test_named_scope_with_include
266
+ project = projects(:active_record)
267
+ entries = project.topics.with_replies_starting_with('AR ').paginate(:page => 1, :per_page => 1)
268
+ assert_equal 1, entries.size
269
+ end
264
270
 
265
271
  ## misc ##
266
272
 
@@ -427,6 +433,12 @@ class FinderTest < ActiveRecordTestCase
427
433
  assert_equal 14, Developer.paginated_each(:page => '2') { }
428
434
  end
429
435
 
436
+ def test_paginated_each_with_named_scope
437
+ assert_equal 2, Developer.poor.paginated_each(:per_page => 1) {
438
+ assert_equal 11, Developer.count
439
+ }
440
+ end
441
+
430
442
  # detect ActiveRecord 2.1
431
443
  if ActiveRecord::Base.private_methods.include?('references_eager_loaded_tables?')
432
444
  def test_removes_irrelevant_includes_in_count
@@ -444,5 +456,21 @@ class FinderTest < ActiveRecordTestCase
444
456
  :include => :projects, :conditions => 'projects.id > 2'
445
457
  end
446
458
  end
459
+
460
+ def test_paginate_from
461
+ result = Developer.paginate(:from => 'users', :page => 1, :per_page => 1)
462
+ assert_equal 1, result.size
463
+ end
464
+
465
+ def test_hmt_with_include
466
+ # ticket #220
467
+ reply = projects(:active_record).replies.find(:first, :order => 'replies.id')
468
+ assert_equal replies(:decisive), reply
469
+
470
+ # ticket #223
471
+ Project.find(1, :include => :replies)
472
+
473
+ # I cannot reproduce any of the failures from those reports :(
474
+ end
447
475
  end
448
476
  end
@@ -3,4 +3,8 @@ class Topic < ActiveRecord::Base
3
3
  belongs_to :project
4
4
 
5
5
  named_scope :mentions_activerecord, :conditions => ['topics.title LIKE ?', '%ActiveRecord%']
6
+
7
+ named_scope :with_replies_starting_with, lambda { |text|
8
+ { :conditions => "replies.content LIKE '#{text}%' ", :include => :replies }
9
+ }
6
10
  end
@@ -41,6 +41,8 @@ class ActiveRecordTestConnector
41
41
  ActiveRecord::Base.logger = Logger.new(STDOUT) if $0 == 'irb'
42
42
  puts "using #{configuration['adapter']} adapter" unless ENV['DB'].blank?
43
43
 
44
+ gem 'sqlite3-ruby' if 'sqlite3' == db
45
+
44
46
  ActiveRecord::Base.establish_connection(configuration)
45
47
  ActiveRecord::Base.configurations = { db => configuration }
46
48
  prepare ActiveRecord::Base.connection
@@ -42,15 +42,21 @@ class WillPaginate::ViewTestCase < Test::Unit::TestCase
42
42
 
43
43
  locals = { :collection => collection, :options => options }
44
44
 
45
- if defined? ActionView::InlineTemplate
46
- # Rails 2.1
47
- args = [ ActionView::InlineTemplate.new(@view, @template, locals) ]
45
+ unless @view.respond_to? :render_template
46
+ # Rails 2.2
47
+ @html_result = ActionView::InlineTemplate.new(@template).render(@view, locals)
48
48
  else
49
- # older Rails versions
50
- args = [nil, @template, nil, locals]
49
+ if defined? ActionView::InlineTemplate
50
+ # Rails 2.1
51
+ args = [ ActionView::InlineTemplate.new(@view, @template, locals) ]
52
+ else
53
+ # older Rails versions
54
+ args = [nil, @template, nil, locals]
55
+ end
56
+
57
+ @html_result = @view.render_template(*args)
51
58
  end
52
59
 
53
- @html_result = @view.render_template(*args)
54
60
  @html_document = HTML::Document.new(@html_result, true, false)
55
61
 
56
62
  if block_given?
@@ -35,7 +35,7 @@ task :test_full => %w(test test_mysql test_postgres)
35
35
  desc %{Test everything with Rails 2.1.x, 2.0.x & 1.2.x gems}
36
36
  task :test_all do
37
37
  all = Rake::Task['test_full']
38
- versions = %w(2.1.0 2.0.2 1.2.6)
38
+ versions = %w(2.1.0 2.0.4 1.2.6)
39
39
  versions.each do |version|
40
40
  ENV['RAILS_VERSION'] = "~> #{version}"
41
41
  all.invoke
@@ -192,13 +192,15 @@ class ViewTest < WillPaginate::ViewTestCase
192
192
  @html_result
193
193
  end
194
194
 
195
- def test_page_entries_info_with_longer_class_name
196
- @template = '<%= page_entries_info collection %>'
197
- collection = ('a'..'z').to_a.paginate
198
- collection.first.stubs(:class).returns(mock('class', :name => 'ProjectType'))
195
+ uses_mocha 'class name' do
196
+ def test_page_entries_info_with_longer_class_name
197
+ @template = '<%= page_entries_info collection %>'
198
+ collection = ('a'..'z').to_a.paginate
199
+ collection.first.stubs(:class).returns(mock('class', :name => 'ProjectType'))
199
200
 
200
- paginate collection
201
- assert @html_result.index('project types'), "expected <#{@html_result.inspect}> to mention 'project types'"
201
+ paginate collection
202
+ assert @html_result.index('project types'), "expected <#{@html_result.inspect}> to mention 'project types'"
203
+ end
202
204
  end
203
205
 
204
206
  def test_page_entries_info_with_single_page_collection
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dweinand-will_paginate
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.3.4
4
+ version: 2.3.7
5
5
  platform: ruby
6
6
  authors:
7
7
  - "Mislav Marohni\xC4\x87"
@@ -10,7 +10,7 @@ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
12
 
13
- date: 2008-09-16 00:00:00 -07:00
13
+ date: 2009-02-10 00:00:00 -08:00
14
14
  default_executable:
15
15
  dependencies: []
16
16