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.
Files changed (56) hide show
  1. data/CHANGELOG.rdoc +105 -0
  2. data/LICENSE +18 -0
  3. data/README.rdoc +125 -0
  4. data/Rakefile +59 -0
  5. data/lib/merbtasks.rb +17 -0
  6. data/lib/will_paginate.rb +40 -0
  7. data/lib/will_paginate/array.rb +35 -0
  8. data/lib/will_paginate/collection.rb +145 -0
  9. data/lib/will_paginate/core_ext.rb +58 -0
  10. data/lib/will_paginate/deprecation.rb +50 -0
  11. data/lib/will_paginate/finders.rb +9 -0
  12. data/lib/will_paginate/finders/active_record.rb +192 -0
  13. data/lib/will_paginate/finders/active_record/named_scope.rb +170 -0
  14. data/lib/will_paginate/finders/active_record/named_scope_patch.rb +39 -0
  15. data/lib/will_paginate/finders/active_resource.rb +51 -0
  16. data/lib/will_paginate/finders/base.rb +112 -0
  17. data/lib/will_paginate/finders/data_mapper.rb +30 -0
  18. data/lib/will_paginate/finders/sequel.rb +21 -0
  19. data/lib/will_paginate/version.rb +9 -0
  20. data/lib/will_paginate/view_helpers.rb +42 -0
  21. data/lib/will_paginate/view_helpers/base.rb +126 -0
  22. data/lib/will_paginate/view_helpers/link_renderer.rb +130 -0
  23. data/lib/will_paginate/view_helpers/link_renderer_base.rb +83 -0
  24. data/lib/will_paginate/view_helpers/merb.rb +13 -0
  25. data/spec/collection_spec.rb +147 -0
  26. data/spec/console +8 -0
  27. data/spec/console_fixtures.rb +8 -0
  28. data/spec/database.yml +22 -0
  29. data/spec/finders/active_record_spec.rb +461 -0
  30. data/spec/finders/active_resource_spec.rb +52 -0
  31. data/spec/finders/activerecord_test_connector.rb +108 -0
  32. data/spec/finders/data_mapper_spec.rb +62 -0
  33. data/spec/finders/data_mapper_test_connector.rb +20 -0
  34. data/spec/finders/sequel_spec.rb +53 -0
  35. data/spec/finders/sequel_test_connector.rb +9 -0
  36. data/spec/finders_spec.rb +76 -0
  37. data/spec/fixtures/admin.rb +3 -0
  38. data/spec/fixtures/developer.rb +13 -0
  39. data/spec/fixtures/developers_projects.yml +13 -0
  40. data/spec/fixtures/project.rb +15 -0
  41. data/spec/fixtures/projects.yml +6 -0
  42. data/spec/fixtures/replies.yml +29 -0
  43. data/spec/fixtures/reply.rb +7 -0
  44. data/spec/fixtures/schema.rb +38 -0
  45. data/spec/fixtures/topic.rb +6 -0
  46. data/spec/fixtures/topics.yml +30 -0
  47. data/spec/fixtures/user.rb +2 -0
  48. data/spec/fixtures/users.yml +35 -0
  49. data/spec/rcov.opts +2 -0
  50. data/spec/spec.opts +2 -0
  51. data/spec/spec_helper.rb +75 -0
  52. data/spec/tasks.rake +60 -0
  53. data/spec/view_helpers/base_spec.rb +64 -0
  54. data/spec/view_helpers/link_renderer_base_spec.rb +84 -0
  55. data/spec/view_helpers/view_example_group.rb +111 -0
  56. 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,9 @@
1
+ require 'sequel'
2
+
3
+ db = Sequel.sqlite
4
+
5
+ db.create_table :cars do
6
+ primary_key :id, :integer, :auto_increment => true
7
+ column :name, :text
8
+ column :notes, :text
9
+ 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,3 @@
1
+ class Admin < User
2
+ has_many :companies, :finder_sql => 'SELECT * FROM companies'
3
+ 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,13 @@
1
+ david_action_controller:
2
+ developer_id: 1
3
+ project_id: 2
4
+ joined_on: 2004-10-10
5
+
6
+ david_active_record:
7
+ developer_id: 1
8
+ project_id: 1
9
+ joined_on: 2004-10-10
10
+
11
+ jamis_active_record:
12
+ developer_id: 2
13
+ project_id: 1
@@ -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,6 @@
1
+ active_record:
2
+ id: 1
3
+ name: Active Record
4
+ action_controller:
5
+ id: 2
6
+ name: Active Controller