myobie-will_paginate 2.3.5
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/CHANGELOG.rdoc +106 -0
- data/LICENSE +18 -0
- data/README.rdoc +107 -0
- data/Rakefile +62 -0
- data/examples/apple-circle.gif +0 -0
- data/examples/index.haml +69 -0
- data/examples/index.html +92 -0
- data/examples/pagination.css +90 -0
- data/examples/pagination.sass +91 -0
- data/init.rb +1 -0
- data/lib/will_paginate.rb +82 -0
- data/lib/will_paginate/array.rb +16 -0
- data/lib/will_paginate/collection.rb +146 -0
- data/lib/will_paginate/core_ext.rb +32 -0
- data/lib/will_paginate/finder.rb +260 -0
- data/lib/will_paginate/named_scope.rb +170 -0
- data/lib/will_paginate/named_scope_patch.rb +37 -0
- data/lib/will_paginate/version.rb +9 -0
- data/lib/will_paginate/view_helpers.rb +383 -0
- data/test/boot.rb +21 -0
- data/test/collection_test.rb +143 -0
- data/test/console +8 -0
- data/test/database.yml +22 -0
- data/test/finder_test.rb +476 -0
- data/test/fixtures/admin.rb +3 -0
- data/test/fixtures/developer.rb +14 -0
- data/test/fixtures/developers_projects.yml +13 -0
- data/test/fixtures/project.rb +15 -0
- data/test/fixtures/projects.yml +6 -0
- data/test/fixtures/replies.yml +29 -0
- data/test/fixtures/reply.rb +7 -0
- data/test/fixtures/schema.rb +38 -0
- data/test/fixtures/topic.rb +10 -0
- data/test/fixtures/topics.yml +30 -0
- data/test/fixtures/user.rb +2 -0
- data/test/fixtures/users.yml +35 -0
- data/test/helper.rb +37 -0
- data/test/lib/activerecord_test_case.rb +36 -0
- data/test/lib/activerecord_test_connector.rb +73 -0
- data/test/lib/load_fixtures.rb +11 -0
- data/test/lib/view_test_process.rb +165 -0
- data/test/tasks.rake +59 -0
- data/test/view_test.rb +363 -0
- metadata +140 -0
@@ -0,0 +1,14 @@
|
|
1
|
+
class Developer < User
|
2
|
+
has_and_belongs_to_many :projects, :include => :topics, :order => 'projects.name'
|
3
|
+
|
4
|
+
def self.with_poor_ones(&block)
|
5
|
+
with_scope :find => { :conditions => ['salary <= ?', 80000], :order => 'salary' } do
|
6
|
+
yield
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
named_scope :distinct, :select => 'DISTINCT `users`.*'
|
11
|
+
named_scope :poor, :conditions => ['salary <= ?', 80000], :order => 'salary'
|
12
|
+
|
13
|
+
def self.per_page() 10 end
|
14
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
class Project < ActiveRecord::Base
|
2
|
+
has_and_belongs_to_many :developers, :uniq => true
|
3
|
+
|
4
|
+
has_many :topics
|
5
|
+
# :finder_sql => 'SELECT * FROM topics WHERE (topics.project_id = #{id})',
|
6
|
+
# :counter_sql => 'SELECT COUNT(*) FROM topics WHERE (topics.project_id = #{id})'
|
7
|
+
|
8
|
+
has_many :replies, :through => :topics do
|
9
|
+
def find_recent(params = {})
|
10
|
+
with_scope :find => { :conditions => ['replies.created_at > ?', 15.minutes.ago] } do
|
11
|
+
find :all, params
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
witty_retort:
|
2
|
+
id: 1
|
3
|
+
topic_id: 1
|
4
|
+
content: Birdman is better!
|
5
|
+
created_at: <%= 6.hours.ago.to_s(:db) %>
|
6
|
+
|
7
|
+
another:
|
8
|
+
id: 2
|
9
|
+
topic_id: 2
|
10
|
+
content: Nuh uh!
|
11
|
+
created_at: <%= 1.hour.ago.to_s(:db) %>
|
12
|
+
|
13
|
+
spam:
|
14
|
+
id: 3
|
15
|
+
topic_id: 1
|
16
|
+
content: Nice site!
|
17
|
+
created_at: <%= 1.hour.ago.to_s(:db) %>
|
18
|
+
|
19
|
+
decisive:
|
20
|
+
id: 4
|
21
|
+
topic_id: 4
|
22
|
+
content: "I'm getting to the bottom of this"
|
23
|
+
created_at: <%= 30.minutes.ago.to_s(:db) %>
|
24
|
+
|
25
|
+
brave:
|
26
|
+
id: 5
|
27
|
+
topic_id: 4
|
28
|
+
content: "AR doesn't scare me a bit"
|
29
|
+
created_at: <%= 10.minutes.ago.to_s(:db) %>
|
@@ -0,0 +1,38 @@
|
|
1
|
+
ActiveRecord::Schema.define do
|
2
|
+
|
3
|
+
create_table "users", :force => true do |t|
|
4
|
+
t.column "name", :text
|
5
|
+
t.column "salary", :integer, :default => 70000
|
6
|
+
t.column "created_at", :datetime
|
7
|
+
t.column "updated_at", :datetime
|
8
|
+
t.column "type", :text
|
9
|
+
end
|
10
|
+
|
11
|
+
create_table "projects", :force => true do |t|
|
12
|
+
t.column "name", :text
|
13
|
+
end
|
14
|
+
|
15
|
+
create_table "developers_projects", :id => false, :force => true do |t|
|
16
|
+
t.column "developer_id", :integer, :null => false
|
17
|
+
t.column "project_id", :integer, :null => false
|
18
|
+
t.column "joined_on", :date
|
19
|
+
t.column "access_level", :integer, :default => 1
|
20
|
+
end
|
21
|
+
|
22
|
+
create_table "topics", :force => true do |t|
|
23
|
+
t.column "project_id", :integer
|
24
|
+
t.column "title", :string
|
25
|
+
t.column "subtitle", :string
|
26
|
+
t.column "content", :text
|
27
|
+
t.column "created_at", :datetime
|
28
|
+
t.column "updated_at", :datetime
|
29
|
+
end
|
30
|
+
|
31
|
+
create_table "replies", :force => true do |t|
|
32
|
+
t.column "content", :text
|
33
|
+
t.column "created_at", :datetime
|
34
|
+
t.column "updated_at", :datetime
|
35
|
+
t.column "topic_id", :integer
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
@@ -0,0 +1,10 @@
|
|
1
|
+
class Topic < ActiveRecord::Base
|
2
|
+
has_many :replies, :dependent => :destroy, :order => 'replies.created_at DESC'
|
3
|
+
belongs_to :project
|
4
|
+
|
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
|
+
}
|
10
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
futurama:
|
2
|
+
id: 1
|
3
|
+
title: Isnt futurama awesome?
|
4
|
+
subtitle: It really is, isnt it.
|
5
|
+
content: I like futurama
|
6
|
+
created_at: <%= 1.day.ago.to_s(:db) %>
|
7
|
+
updated_at:
|
8
|
+
|
9
|
+
harvey_birdman:
|
10
|
+
id: 2
|
11
|
+
title: Harvey Birdman is the king of all men
|
12
|
+
subtitle: yup
|
13
|
+
content: He really is
|
14
|
+
created_at: <%= 2.hours.ago.to_s(:db) %>
|
15
|
+
updated_at:
|
16
|
+
|
17
|
+
rails:
|
18
|
+
id: 3
|
19
|
+
project_id: 1
|
20
|
+
title: Rails is nice
|
21
|
+
subtitle: It makes me happy
|
22
|
+
content: except when I have to hack internals to fix pagination. even then really.
|
23
|
+
created_at: <%= 20.minutes.ago.to_s(:db) %>
|
24
|
+
|
25
|
+
ar:
|
26
|
+
id: 4
|
27
|
+
project_id: 1
|
28
|
+
title: ActiveRecord sometimes freaks me out
|
29
|
+
content: "I mean, what's the deal with eager loading?"
|
30
|
+
created_at: <%= 15.minutes.ago.to_s(:db) %>
|
@@ -0,0 +1,35 @@
|
|
1
|
+
david:
|
2
|
+
id: 1
|
3
|
+
name: David
|
4
|
+
salary: 80000
|
5
|
+
type: Developer
|
6
|
+
|
7
|
+
jamis:
|
8
|
+
id: 2
|
9
|
+
name: Jamis
|
10
|
+
salary: 150000
|
11
|
+
type: Developer
|
12
|
+
|
13
|
+
<% for digit in 3..10 %>
|
14
|
+
dev_<%= digit %>:
|
15
|
+
id: <%= digit %>
|
16
|
+
name: fixture_<%= digit %>
|
17
|
+
salary: 100000
|
18
|
+
type: Developer
|
19
|
+
<% end %>
|
20
|
+
|
21
|
+
poor_jamis:
|
22
|
+
id: 11
|
23
|
+
name: Jamis
|
24
|
+
salary: 9000
|
25
|
+
type: Developer
|
26
|
+
|
27
|
+
admin:
|
28
|
+
id: 12
|
29
|
+
name: admin
|
30
|
+
type: Admin
|
31
|
+
|
32
|
+
goofy:
|
33
|
+
id: 13
|
34
|
+
name: Goofy
|
35
|
+
type: Admin
|
data/test/helper.rb
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
require 'rubygems'
|
3
|
+
|
4
|
+
# gem install redgreen for colored test output
|
5
|
+
begin require 'redgreen'; rescue LoadError; end
|
6
|
+
|
7
|
+
require 'boot' unless defined?(ActiveRecord)
|
8
|
+
|
9
|
+
class Test::Unit::TestCase
|
10
|
+
protected
|
11
|
+
def assert_respond_to_all object, methods
|
12
|
+
methods.each do |method|
|
13
|
+
[method.to_s, method.to_sym].each { |m| assert_respond_to object, m }
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def collect_deprecations
|
18
|
+
old_behavior = WillPaginate::Deprecation.behavior
|
19
|
+
deprecations = []
|
20
|
+
WillPaginate::Deprecation.behavior = Proc.new do |message, callstack|
|
21
|
+
deprecations << message
|
22
|
+
end
|
23
|
+
result = yield
|
24
|
+
[result, deprecations]
|
25
|
+
ensure
|
26
|
+
WillPaginate::Deprecation.behavior = old_behavior
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
# Wrap tests that use Mocha and skip if unavailable.
|
31
|
+
def uses_mocha(test_name)
|
32
|
+
require 'mocha' unless Object.const_defined?(:Mocha)
|
33
|
+
rescue LoadError => load_error
|
34
|
+
$stderr.puts "Skipping #{test_name} tests. `gem install mocha` and try again."
|
35
|
+
else
|
36
|
+
yield
|
37
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require 'lib/activerecord_test_connector'
|
2
|
+
|
3
|
+
class ActiveRecordTestCase < Test::Unit::TestCase
|
4
|
+
# Set our fixture path
|
5
|
+
if ActiveRecordTestConnector.able_to_connect
|
6
|
+
self.fixture_path = File.join(File.dirname(__FILE__), '..', 'fixtures')
|
7
|
+
self.use_transactional_fixtures = true
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.fixtures(*args)
|
11
|
+
super if ActiveRecordTestConnector.connected
|
12
|
+
end
|
13
|
+
|
14
|
+
def run(*args)
|
15
|
+
super if ActiveRecordTestConnector.connected
|
16
|
+
end
|
17
|
+
|
18
|
+
# Default so Test::Unit::TestCase doesn't complain
|
19
|
+
def test_truth
|
20
|
+
end
|
21
|
+
|
22
|
+
protected
|
23
|
+
|
24
|
+
def assert_queries(num = 1)
|
25
|
+
$query_count = 0
|
26
|
+
yield
|
27
|
+
ensure
|
28
|
+
assert_equal num, $query_count, "#{$query_count} instead of #{num} queries were executed."
|
29
|
+
end
|
30
|
+
|
31
|
+
def assert_no_queries(&block)
|
32
|
+
assert_queries(0, &block)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
ActiveRecordTestConnector.setup
|
@@ -0,0 +1,73 @@
|
|
1
|
+
require 'active_record'
|
2
|
+
require 'active_record/version'
|
3
|
+
require 'active_record/fixtures'
|
4
|
+
|
5
|
+
class ActiveRecordTestConnector
|
6
|
+
cattr_accessor :able_to_connect
|
7
|
+
cattr_accessor :connected
|
8
|
+
|
9
|
+
FIXTURES_PATH = File.join(File.dirname(__FILE__), '..', 'fixtures')
|
10
|
+
|
11
|
+
# Set our defaults
|
12
|
+
self.connected = false
|
13
|
+
self.able_to_connect = true
|
14
|
+
|
15
|
+
def self.setup
|
16
|
+
unless self.connected || !self.able_to_connect
|
17
|
+
setup_connection
|
18
|
+
load_schema
|
19
|
+
add_load_path FIXTURES_PATH
|
20
|
+
self.connected = true
|
21
|
+
end
|
22
|
+
rescue Exception => e # errors from ActiveRecord setup
|
23
|
+
$stderr.puts "\nSkipping ActiveRecord tests: #{e}\n\n"
|
24
|
+
self.able_to_connect = false
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
def self.add_load_path(path)
|
30
|
+
dep = defined?(ActiveSupport::Dependencies) ? ActiveSupport::Dependencies : ::Dependencies
|
31
|
+
dep.load_paths.unshift path
|
32
|
+
end
|
33
|
+
|
34
|
+
def self.setup_connection
|
35
|
+
db = ENV['DB'].blank?? 'sqlite3' : ENV['DB']
|
36
|
+
|
37
|
+
configurations = YAML.load_file(File.join(File.dirname(__FILE__), '..', 'database.yml'))
|
38
|
+
raise "no configuration for '#{db}'" unless configurations.key? db
|
39
|
+
configuration = configurations[db]
|
40
|
+
|
41
|
+
ActiveRecord::Base.logger = Logger.new(STDOUT) if $0 == 'irb'
|
42
|
+
puts "using #{configuration['adapter']} adapter" unless ENV['DB'].blank?
|
43
|
+
|
44
|
+
ActiveRecord::Base.establish_connection(configuration)
|
45
|
+
ActiveRecord::Base.configurations = { db => configuration }
|
46
|
+
prepare ActiveRecord::Base.connection
|
47
|
+
|
48
|
+
unless Object.const_defined?(:QUOTED_TYPE)
|
49
|
+
Object.send :const_set, :QUOTED_TYPE, ActiveRecord::Base.connection.quote_column_name('type')
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def self.load_schema
|
54
|
+
ActiveRecord::Base.silence do
|
55
|
+
ActiveRecord::Migration.verbose = false
|
56
|
+
load File.join(FIXTURES_PATH, 'schema.rb')
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def self.prepare(conn)
|
61
|
+
class << conn
|
62
|
+
IGNORED_SQL = [/^PRAGMA/, /^SELECT currval/, /^SELECT CAST/, /^SELECT @@IDENTITY/, /^SELECT @@ROWCOUNT/, /^SHOW FIELDS /]
|
63
|
+
|
64
|
+
def execute_with_counting(sql, name = nil, &block)
|
65
|
+
$query_count ||= 0
|
66
|
+
$query_count += 1 unless IGNORED_SQL.any? { |r| sql =~ r }
|
67
|
+
execute_without_counting(sql, name, &block)
|
68
|
+
end
|
69
|
+
|
70
|
+
alias_method_chain :execute, :counting
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
require 'boot'
|
2
|
+
require 'lib/activerecord_test_connector'
|
3
|
+
|
4
|
+
# setup the connection
|
5
|
+
ActiveRecordTestConnector.setup
|
6
|
+
|
7
|
+
# load all fixtures
|
8
|
+
Fixtures.create_fixtures(ActiveRecordTestConnector::FIXTURES_PATH, ActiveRecord::Base.connection.tables)
|
9
|
+
|
10
|
+
require 'will_paginate'
|
11
|
+
WillPaginate.enable_activerecord
|
@@ -0,0 +1,165 @@
|
|
1
|
+
require 'action_controller'
|
2
|
+
require 'action_controller/test_process'
|
3
|
+
|
4
|
+
require 'will_paginate'
|
5
|
+
WillPaginate.enable_actionpack
|
6
|
+
|
7
|
+
ActionController::Routing::Routes.draw do |map|
|
8
|
+
map.connect 'dummy/page/:page', :controller => 'dummy'
|
9
|
+
map.connect 'dummy/dots/page.:page', :controller => 'dummy', :action => 'dots'
|
10
|
+
map.connect 'ibocorp/:page', :controller => 'ibocorp',
|
11
|
+
:requirements => { :page => /\d+/ },
|
12
|
+
:defaults => { :page => 1 }
|
13
|
+
|
14
|
+
map.connect ':controller/:action/:id'
|
15
|
+
end
|
16
|
+
|
17
|
+
ActionController::Base.perform_caching = false
|
18
|
+
|
19
|
+
class WillPaginate::ViewTestCase < Test::Unit::TestCase
|
20
|
+
def setup
|
21
|
+
super
|
22
|
+
@controller = DummyController.new
|
23
|
+
@request = @controller.request
|
24
|
+
@html_result = nil
|
25
|
+
@template = '<%= will_paginate collection, options %>'
|
26
|
+
|
27
|
+
@view = ActionView::Base.new
|
28
|
+
@view.assigns['controller'] = @controller
|
29
|
+
@view.assigns['_request'] = @request
|
30
|
+
@view.assigns['_params'] = @request.params
|
31
|
+
end
|
32
|
+
|
33
|
+
def test_no_complain; end
|
34
|
+
|
35
|
+
protected
|
36
|
+
|
37
|
+
def paginate(collection = {}, options = {}, &block)
|
38
|
+
if collection.instance_of? Hash
|
39
|
+
page_options = { :page => 1, :total_entries => 11, :per_page => 4 }.merge(collection)
|
40
|
+
collection = [1].paginate(page_options)
|
41
|
+
end
|
42
|
+
|
43
|
+
locals = { :collection => collection, :options => options }
|
44
|
+
|
45
|
+
if defined? ActionView::InlineTemplate
|
46
|
+
# Rails 2.1
|
47
|
+
args = [ ActionView::InlineTemplate.new(@view, @template, locals) ]
|
48
|
+
else
|
49
|
+
# older Rails versions
|
50
|
+
args = [nil, @template, nil, locals]
|
51
|
+
end
|
52
|
+
|
53
|
+
@html_result = @view.render_template(*args)
|
54
|
+
@html_document = HTML::Document.new(@html_result, true, false)
|
55
|
+
|
56
|
+
if block_given?
|
57
|
+
classname = options[:class] || WillPaginate::ViewHelpers.pagination_options[:class]
|
58
|
+
assert_select("div.#{classname}", 1, 'no main DIV', &block)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def response_from_page_or_rjs
|
63
|
+
@html_document.root
|
64
|
+
end
|
65
|
+
|
66
|
+
def validate_page_numbers expected, links, param_name = :page
|
67
|
+
param_pattern = /\W#{CGI.escape(param_name.to_s)}=([^&]*)/
|
68
|
+
|
69
|
+
assert_equal(expected, links.map { |e|
|
70
|
+
e['href'] =~ param_pattern
|
71
|
+
$1 ? $1.to_i : $1
|
72
|
+
})
|
73
|
+
end
|
74
|
+
|
75
|
+
def assert_links_match pattern, links = nil, numbers = nil
|
76
|
+
links ||= assert_select 'div.pagination a[href]' do |elements|
|
77
|
+
elements
|
78
|
+
end
|
79
|
+
|
80
|
+
pages = [] if numbers
|
81
|
+
|
82
|
+
links.each do |el|
|
83
|
+
assert_match pattern, el['href']
|
84
|
+
if numbers
|
85
|
+
el['href'] =~ pattern
|
86
|
+
pages << ($1.nil?? nil : $1.to_i)
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
assert_equal numbers, pages, "page numbers don't match" if numbers
|
91
|
+
end
|
92
|
+
|
93
|
+
def assert_no_links_match pattern
|
94
|
+
assert_select 'div.pagination a[href]' do |elements|
|
95
|
+
elements.each do |el|
|
96
|
+
assert_no_match pattern, el['href']
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
class DummyRequest
|
103
|
+
attr_accessor :symbolized_path_parameters
|
104
|
+
|
105
|
+
def initialize
|
106
|
+
@get = true
|
107
|
+
@params = {}
|
108
|
+
@symbolized_path_parameters = { :controller => 'foo', :action => 'bar' }
|
109
|
+
end
|
110
|
+
|
111
|
+
def get?
|
112
|
+
@get
|
113
|
+
end
|
114
|
+
|
115
|
+
def post
|
116
|
+
@get = false
|
117
|
+
end
|
118
|
+
|
119
|
+
def relative_url_root
|
120
|
+
''
|
121
|
+
end
|
122
|
+
|
123
|
+
def params(more = nil)
|
124
|
+
@params.update(more) if more
|
125
|
+
@params
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
class DummyController
|
130
|
+
attr_reader :request
|
131
|
+
attr_accessor :controller_name
|
132
|
+
|
133
|
+
def initialize
|
134
|
+
@request = DummyRequest.new
|
135
|
+
@url = ActionController::UrlRewriter.new(@request, @request.params)
|
136
|
+
end
|
137
|
+
|
138
|
+
def params
|
139
|
+
@request.params
|
140
|
+
end
|
141
|
+
|
142
|
+
def url_for(params)
|
143
|
+
@url.rewrite(params)
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
module HTML
|
148
|
+
Node.class_eval do
|
149
|
+
def inner_text
|
150
|
+
children.map(&:inner_text).join('')
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
Text.class_eval do
|
155
|
+
def inner_text
|
156
|
+
self.to_s
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
Tag.class_eval do
|
161
|
+
def inner_text
|
162
|
+
childless?? '' : super
|
163
|
+
end
|
164
|
+
end
|
165
|
+
end
|