merb_paginate 0.9.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/CHANGELOG.rdoc +105 -0
- data/LICENSE +18 -0
- data/README.rdoc +125 -0
- data/Rakefile +59 -0
- data/lib/merbtasks.rb +17 -0
- data/lib/will_paginate.rb +40 -0
- data/lib/will_paginate/array.rb +35 -0
- data/lib/will_paginate/collection.rb +145 -0
- data/lib/will_paginate/core_ext.rb +58 -0
- data/lib/will_paginate/deprecation.rb +50 -0
- data/lib/will_paginate/finders.rb +9 -0
- data/lib/will_paginate/finders/active_record.rb +192 -0
- data/lib/will_paginate/finders/active_record/named_scope.rb +170 -0
- data/lib/will_paginate/finders/active_record/named_scope_patch.rb +39 -0
- data/lib/will_paginate/finders/active_resource.rb +51 -0
- data/lib/will_paginate/finders/base.rb +112 -0
- data/lib/will_paginate/finders/data_mapper.rb +30 -0
- data/lib/will_paginate/finders/sequel.rb +21 -0
- data/lib/will_paginate/version.rb +9 -0
- data/lib/will_paginate/view_helpers.rb +42 -0
- data/lib/will_paginate/view_helpers/base.rb +126 -0
- data/lib/will_paginate/view_helpers/link_renderer.rb +130 -0
- data/lib/will_paginate/view_helpers/link_renderer_base.rb +83 -0
- data/lib/will_paginate/view_helpers/merb.rb +13 -0
- data/spec/collection_spec.rb +147 -0
- data/spec/console +8 -0
- data/spec/console_fixtures.rb +8 -0
- data/spec/database.yml +22 -0
- data/spec/finders/active_record_spec.rb +461 -0
- data/spec/finders/active_resource_spec.rb +52 -0
- data/spec/finders/activerecord_test_connector.rb +108 -0
- data/spec/finders/data_mapper_spec.rb +62 -0
- data/spec/finders/data_mapper_test_connector.rb +20 -0
- data/spec/finders/sequel_spec.rb +53 -0
- data/spec/finders/sequel_test_connector.rb +9 -0
- data/spec/finders_spec.rb +76 -0
- data/spec/fixtures/admin.rb +3 -0
- data/spec/fixtures/developer.rb +13 -0
- data/spec/fixtures/developers_projects.yml +13 -0
- data/spec/fixtures/project.rb +15 -0
- data/spec/fixtures/projects.yml +6 -0
- data/spec/fixtures/replies.yml +29 -0
- data/spec/fixtures/reply.rb +7 -0
- data/spec/fixtures/schema.rb +38 -0
- data/spec/fixtures/topic.rb +6 -0
- data/spec/fixtures/topics.yml +30 -0
- data/spec/fixtures/user.rb +2 -0
- data/spec/fixtures/users.yml +35 -0
- data/spec/rcov.opts +2 -0
- data/spec/spec.opts +2 -0
- data/spec/spec_helper.rb +75 -0
- data/spec/tasks.rake +60 -0
- data/spec/view_helpers/base_spec.rb +64 -0
- data/spec/view_helpers/link_renderer_base_spec.rb +84 -0
- data/spec/view_helpers/view_example_group.rb +111 -0
- metadata +126 -0
@@ -0,0 +1,52 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'will_paginate/finders/active_resource'
|
3
|
+
require 'active_resource/http_mock'
|
4
|
+
|
5
|
+
class AresProject < ActiveResource::Base
|
6
|
+
self.site = 'http://localhost:4000'
|
7
|
+
end
|
8
|
+
|
9
|
+
describe WillPaginate::Finders::ActiveResource do
|
10
|
+
|
11
|
+
before :all do
|
12
|
+
# ActiveResource::HttpMock.respond_to do |mock|
|
13
|
+
# mock.get "/ares_projects.xml?page=1&per_page=5", {}, [].to_xml
|
14
|
+
# end
|
15
|
+
end
|
16
|
+
|
17
|
+
it "should integrate with ActiveResource::Base" do
|
18
|
+
ActiveResource::Base.should respond_to(:paginate)
|
19
|
+
end
|
20
|
+
|
21
|
+
it "should error when no parameters for #paginate" do
|
22
|
+
lambda { AresProject.paginate }.should raise_error(ArgumentError)
|
23
|
+
end
|
24
|
+
|
25
|
+
it "should paginate" do
|
26
|
+
AresProject.expects(:find_every).with(:params => { :page => 1, :per_page => 5 }).returns([])
|
27
|
+
AresProject.paginate(:page => 1, :per_page => 5)
|
28
|
+
end
|
29
|
+
|
30
|
+
it "should have 30 per_page as default" do
|
31
|
+
AresProject.expects(:find_every).with(:params => { :page => 1, :per_page => 30 }).returns([])
|
32
|
+
AresProject.paginate(:page => 1)
|
33
|
+
end
|
34
|
+
|
35
|
+
it "should support #paginate(:all)" do
|
36
|
+
lambda { AresProject.paginate(:all) }.should raise_error(ArgumentError)
|
37
|
+
end
|
38
|
+
|
39
|
+
it "should error #paginate(:other)" do
|
40
|
+
lambda { AresProject.paginate(:first) }.should raise_error(ArgumentError)
|
41
|
+
end
|
42
|
+
|
43
|
+
protected
|
44
|
+
|
45
|
+
def create(page = 2, limit = 5, total = nil, &block)
|
46
|
+
if block_given?
|
47
|
+
WillPaginate::Collection.create(page, limit, total, &block)
|
48
|
+
else
|
49
|
+
WillPaginate::Collection.new(page, limit, total)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,108 @@
|
|
1
|
+
require 'active_record'
|
2
|
+
require 'active_record/version'
|
3
|
+
require 'active_record/fixtures'
|
4
|
+
require 'active_support/multibyte' # needed for Ruby 1.9.1
|
5
|
+
|
6
|
+
class ActiverecordTestConnector
|
7
|
+
cattr_accessor :able_to_connect
|
8
|
+
cattr_accessor :connected
|
9
|
+
|
10
|
+
FIXTURES_PATH = File.join(File.dirname(__FILE__), '..', 'fixtures')
|
11
|
+
|
12
|
+
# Set our defaults
|
13
|
+
self.connected = false
|
14
|
+
self.able_to_connect = true
|
15
|
+
|
16
|
+
def self.setup
|
17
|
+
unless self.connected || !self.able_to_connect
|
18
|
+
setup_connection
|
19
|
+
load_schema
|
20
|
+
add_load_path FIXTURES_PATH
|
21
|
+
self.connected = true
|
22
|
+
end
|
23
|
+
rescue Exception => e # errors from ActiveRecord setup
|
24
|
+
$stderr.puts "\nSkipping ActiveRecord tests: #{e}\n\n"
|
25
|
+
self.able_to_connect = false
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
def self.add_load_path(path)
|
31
|
+
dep = defined?(ActiveSupport::Dependencies) ? ActiveSupport::Dependencies : ::Dependencies
|
32
|
+
dep.load_paths.unshift path
|
33
|
+
end
|
34
|
+
|
35
|
+
def self.setup_connection
|
36
|
+
db = ENV['DB'].blank?? 'sqlite3' : ENV['DB']
|
37
|
+
|
38
|
+
configurations = YAML.load_file(File.join(File.dirname(__FILE__), '..', 'database.yml'))
|
39
|
+
raise "no configuration for '#{db}'" unless configurations.key? db
|
40
|
+
configuration = configurations[db]
|
41
|
+
|
42
|
+
ActiveRecord::Base.logger = Logger.new(STDOUT) if $0 == 'irb'
|
43
|
+
puts "using #{configuration['adapter']} adapter" unless ENV['DB'].blank?
|
44
|
+
|
45
|
+
ActiveRecord::Base.establish_connection(configuration)
|
46
|
+
ActiveRecord::Base.configurations = { db => configuration }
|
47
|
+
prepare ActiveRecord::Base.connection
|
48
|
+
|
49
|
+
unless Object.const_defined?(:QUOTED_TYPE)
|
50
|
+
Object.send :const_set, :QUOTED_TYPE, ActiveRecord::Base.connection.quote_column_name('type')
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def self.load_schema
|
55
|
+
ActiveRecord::Base.silence do
|
56
|
+
ActiveRecord::Migration.verbose = false
|
57
|
+
load File.join(FIXTURES_PATH, 'schema.rb')
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def self.prepare(conn)
|
62
|
+
class << conn
|
63
|
+
IGNORED_SQL = [/^PRAGMA/, /^SELECT currval/, /^SELECT CAST/, /^SELECT @@IDENTITY/, /^SELECT @@ROWCOUNT/, /^SHOW FIELDS /]
|
64
|
+
|
65
|
+
def execute_with_counting(sql, name = nil, &block)
|
66
|
+
$query_count ||= 0
|
67
|
+
$query_count += 1 unless IGNORED_SQL.any? { |r| sql =~ r }
|
68
|
+
execute_without_counting(sql, name, &block)
|
69
|
+
end
|
70
|
+
|
71
|
+
alias_method_chain :execute, :counting
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
module FixtureSetup
|
76
|
+
def fixtures(*tables)
|
77
|
+
table_names = tables.map { |t| t.to_s }
|
78
|
+
|
79
|
+
fixtures = Fixtures.create_fixtures ActiverecordTestConnector::FIXTURES_PATH, table_names
|
80
|
+
@@loaded_fixtures = {}
|
81
|
+
@@fixture_cache = {}
|
82
|
+
|
83
|
+
unless fixtures.nil?
|
84
|
+
if fixtures.instance_of?(Fixtures)
|
85
|
+
@@loaded_fixtures[fixtures.table_name] = fixtures
|
86
|
+
else
|
87
|
+
fixtures.each { |f| @@loaded_fixtures[f.table_name] = f }
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
table_names.each do |table_name|
|
92
|
+
define_method(table_name) do |*fixtures|
|
93
|
+
@@fixture_cache[table_name] ||= {}
|
94
|
+
|
95
|
+
instances = fixtures.map do |fixture|
|
96
|
+
if @@loaded_fixtures[table_name][fixture.to_s]
|
97
|
+
@@fixture_cache[table_name][fixture] ||= @@loaded_fixtures[table_name][fixture.to_s].find
|
98
|
+
else
|
99
|
+
raise StandardError, "No fixture with name '#{fixture}' found for table '#{table_name}'"
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
instances.size == 1 ? instances.first : instances
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'will_paginate/finders/data_mapper'
|
3
|
+
require File.dirname(__FILE__) + '/data_mapper_test_connector'
|
4
|
+
|
5
|
+
require 'will_paginate'
|
6
|
+
|
7
|
+
describe WillPaginate::Finders::DataMapper do
|
8
|
+
|
9
|
+
it "should make #paginate available to DM resource classes" do
|
10
|
+
Animal.should respond_to(:paginate)
|
11
|
+
end
|
12
|
+
|
13
|
+
it "should paginate" do
|
14
|
+
Animal.expects(:all).with(:limit => 5, :offset => 0).returns([])
|
15
|
+
Animal.paginate(:page => 1, :per_page => 5)
|
16
|
+
end
|
17
|
+
|
18
|
+
it "should NOT to paginate_by_sql" do
|
19
|
+
Animal.should_not respond_to(:paginate_by_sql)
|
20
|
+
end
|
21
|
+
|
22
|
+
it "should support explicit :all argument" do
|
23
|
+
Animal.expects(:all).with(instance_of(Hash)).returns([])
|
24
|
+
Animal.paginate(:all, :page => nil)
|
25
|
+
end
|
26
|
+
|
27
|
+
it "should support conditional pagination" do
|
28
|
+
filtered_result = Animal.paginate(:all, :name => 'Dog', :page => nil)
|
29
|
+
filtered_result.size.should == 1
|
30
|
+
filtered_result.first.should == Animal.first(:name => 'Dog')
|
31
|
+
end
|
32
|
+
|
33
|
+
it "should leave extra parameters intact" do
|
34
|
+
Animal.expects(:all).with(:name => 'Dog', :limit => 4, :offset => 0 ).returns(Array.new(5))
|
35
|
+
Animal.expects(:count).with({:name => 'Dog'}).returns(1)
|
36
|
+
|
37
|
+
Animal.paginate :name => 'Dog', :page => 1, :per_page => 4
|
38
|
+
end
|
39
|
+
|
40
|
+
describe "counting" do
|
41
|
+
it "should ignore nil in :count parameter" do
|
42
|
+
lambda { Animal.paginate :page => nil, :count => nil }.should_not raise_error
|
43
|
+
end
|
44
|
+
|
45
|
+
it "should guess the total count" do
|
46
|
+
Animal.expects(:all).returns(Array.new(2))
|
47
|
+
Animal.expects(:count).never
|
48
|
+
|
49
|
+
result = Animal.paginate :page => 2, :per_page => 4
|
50
|
+
result.total_entries.should == 6
|
51
|
+
end
|
52
|
+
|
53
|
+
it "should guess that there are no records" do
|
54
|
+
Animal.expects(:all).returns([])
|
55
|
+
Animal.expects(:count).never
|
56
|
+
|
57
|
+
result = Animal.paginate :page => 1, :per_page => 4
|
58
|
+
result.total_entries.should == 0
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'dm-core'
|
2
|
+
DataMapper.setup :default, 'sqlite3::memory:'
|
3
|
+
|
4
|
+
# Define models
|
5
|
+
class Animal
|
6
|
+
include DataMapper::Resource
|
7
|
+
property :id, Serial
|
8
|
+
property :name, String
|
9
|
+
property :notes, Text
|
10
|
+
|
11
|
+
def self.setup
|
12
|
+
Animal.create(:name => 'Dog', :notes => "Man's best friend")
|
13
|
+
Animal.create(:name => 'Cat', :notes => "Woman's best friend")
|
14
|
+
Animal.create(:name => 'Lion', :notes => 'King of the Jungle')
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
# Load fixtures
|
19
|
+
Animal.auto_migrate!
|
20
|
+
Animal.setup
|
@@ -0,0 +1,53 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'will_paginate/finders/sequel'
|
3
|
+
require File.dirname(__FILE__) + '/sequel_test_connector'
|
4
|
+
|
5
|
+
describe Sequel::Dataset::Pagination, 'extension' do
|
6
|
+
|
7
|
+
class Car < Sequel::Model
|
8
|
+
end
|
9
|
+
|
10
|
+
it "should have the #paginate method" do
|
11
|
+
Car.should respond_to(:paginate)
|
12
|
+
end
|
13
|
+
|
14
|
+
it "should NOT have the #paginate_by_sql method" do
|
15
|
+
Car.should_not respond_to(:paginate_by_sql)
|
16
|
+
end
|
17
|
+
|
18
|
+
describe 'pagination' do
|
19
|
+
before(:all) do
|
20
|
+
Car.create(:name => 'Shelby', :notes => "Man's best friend")
|
21
|
+
Car.create(:name => 'Aston Martin', :notes => "Woman's best friend")
|
22
|
+
Car.create(:name => 'Corvette', :notes => 'King of the Jungle')
|
23
|
+
end
|
24
|
+
|
25
|
+
it "should imitate WillPaginate::Collection" do
|
26
|
+
result = Car.paginate(1, 2)
|
27
|
+
|
28
|
+
result.total_entries.should == 3
|
29
|
+
result.total_pages.should == 2
|
30
|
+
result.per_page.should == 2
|
31
|
+
result.current_page.should == 1
|
32
|
+
result.previous_page.should be_nil
|
33
|
+
result.next_page.should == 2
|
34
|
+
end
|
35
|
+
|
36
|
+
it "should perform" do
|
37
|
+
Car.paginate(1, 2).all.should == [Car[1], Car[2]]
|
38
|
+
end
|
39
|
+
|
40
|
+
it "should perform with #select and #order" do
|
41
|
+
result = Car.select("name as foo".lit).order(:name).paginate(1, 2).all
|
42
|
+
result.size.should == 2
|
43
|
+
result.first.values[:foo].should == "Aston Martin"
|
44
|
+
end
|
45
|
+
|
46
|
+
it "should perform with #filter" do
|
47
|
+
results = Car.filter(:name => 'Shelby').paginate(1, 2).all
|
48
|
+
results.size.should == 1
|
49
|
+
results.first.should == Car.find(:name => 'Shelby')
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
end
|
@@ -0,0 +1,76 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'will_paginate/finders/base'
|
3
|
+
|
4
|
+
class Model
|
5
|
+
extend WillPaginate::Finders::Base
|
6
|
+
end
|
7
|
+
|
8
|
+
describe WillPaginate::Finders::Base do
|
9
|
+
it "should define default per_page of 30" do
|
10
|
+
Model.per_page.should == 30
|
11
|
+
end
|
12
|
+
|
13
|
+
it "should allow to set custom per_page" do
|
14
|
+
begin
|
15
|
+
Model.per_page = 25
|
16
|
+
Model.per_page.should == 25
|
17
|
+
ensure
|
18
|
+
Model.per_page = 30
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
it "should result with WillPaginate::Collection" do
|
23
|
+
Model.expects(:wp_query)
|
24
|
+
Model.paginate(:page => nil).should be_instance_of(WillPaginate::Collection)
|
25
|
+
end
|
26
|
+
|
27
|
+
it "should delegate pagination to wp_query" do
|
28
|
+
Model.expects(:wp_query).with({}, instance_of(WillPaginate::Collection), [])
|
29
|
+
Model.paginate :page => nil
|
30
|
+
end
|
31
|
+
|
32
|
+
it "should complain when no hash parameters given" do
|
33
|
+
lambda {
|
34
|
+
Model.paginate
|
35
|
+
}.should raise_error(ArgumentError, 'parameter hash expected')
|
36
|
+
end
|
37
|
+
|
38
|
+
it "should complain when no :page parameter present" do
|
39
|
+
lambda {
|
40
|
+
Model.paginate :per_page => 6
|
41
|
+
}.should raise_error(ArgumentError, ':page parameter required')
|
42
|
+
end
|
43
|
+
|
44
|
+
it "should complain when both :count and :total_entries are given" do
|
45
|
+
lambda {
|
46
|
+
Model.paginate :page => 1, :count => {}, :total_entries => 1
|
47
|
+
}.should raise_error(ArgumentError, ':count and :total_entries are mutually exclusive')
|
48
|
+
end
|
49
|
+
|
50
|
+
it "should never mangle options" do
|
51
|
+
options = { :page => 1 }
|
52
|
+
options.expects(:delete).never
|
53
|
+
options_before = options.dup
|
54
|
+
|
55
|
+
Model.expects(:wp_query)
|
56
|
+
Model.paginate(options)
|
57
|
+
|
58
|
+
options.should == options_before
|
59
|
+
end
|
60
|
+
|
61
|
+
it "should provide paginated_each functionality" do
|
62
|
+
collection = stub('collection', :size => 5, :empty? => false, :per_page => 5)
|
63
|
+
collection.expects(:each).times(2).returns(collection)
|
64
|
+
last_collection = stub('collection', :size => 4, :empty? => false, :per_page => 5)
|
65
|
+
last_collection.expects(:each).returns(last_collection)
|
66
|
+
|
67
|
+
params = { :order => 'id', :total_entries => 0 }
|
68
|
+
|
69
|
+
Model.expects(:paginate).with(params.merge(:page => 2)).returns(collection)
|
70
|
+
Model.expects(:paginate).with(params.merge(:page => 3)).returns(collection)
|
71
|
+
Model.expects(:paginate).with(params.merge(:page => 4)).returns(last_collection)
|
72
|
+
|
73
|
+
total = Model.paginated_each(:page => '2') { }
|
74
|
+
total.should == 14
|
75
|
+
end
|
76
|
+
end
|
@@ -0,0 +1,13 @@
|
|
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 :poor, :conditions => ['salary <= ?', 80000], :order => 'salary'
|
11
|
+
|
12
|
+
def self.per_page() 10 end
|
13
|
+
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
|