Commit 4acbfa29ca932a6b50935f581f2cc2bab2c3bc30
1 parent
6e4a7b04
Exists in
master
and in
29 other branches
rails3: updating will_paginate library
Showing
68 changed files
with
4612 additions
and
0 deletions
Show diff stats
@@ -0,0 +1 @@ | @@ -0,0 +1 @@ | ||
1 | +--color |
@@ -0,0 +1,26 @@ | @@ -0,0 +1,26 @@ | ||
1 | +bundler_args: "--standalone --binstubs --without development" | ||
2 | +script: script/test_all | ||
3 | +services: mongodb | ||
4 | +before_script: | ||
5 | + - mysql -e 'create database will_paginate;' | ||
6 | + - psql -c 'create database will_paginate;' -U postgres | ||
7 | +rvm: | ||
8 | + - 1.8.7 | ||
9 | + - 1.9.2 | ||
10 | + - 1.9.3 | ||
11 | +gemfile: | ||
12 | + - Gemfile | ||
13 | + - Gemfile.rails3.0 | ||
14 | + - Gemfile.rails3.1 | ||
15 | + - Gemfile.rails3.2 | ||
16 | + - Gemfile.rails-edge | ||
17 | +matrix: | ||
18 | + exclude: | ||
19 | + - rvm: 1.8.7 | ||
20 | + gemfile: Gemfile.rails-edge | ||
21 | + - rvm: 1.8.7 | ||
22 | + gemfile: Gemfile | ||
23 | + - rvm: 1.9.2 | ||
24 | + gemfile: Gemfile.rails-edge | ||
25 | + - rvm: 1.9.2 | ||
26 | + gemfile: Gemfile |
@@ -0,0 +1,22 @@ | @@ -0,0 +1,22 @@ | ||
1 | +source 'https://rubygems.org' | ||
2 | + | ||
3 | +rails_version = '~> 4.0.0.rc2' | ||
4 | + | ||
5 | +gem 'activerecord', rails_version | ||
6 | +gem 'actionpack', rails_version | ||
7 | + | ||
8 | +gem 'rspec', '~> 2.6.0' | ||
9 | +gem 'mocha', '~> 0.9.8' | ||
10 | + | ||
11 | +gem 'sqlite3', '~> 1.3.6' | ||
12 | + | ||
13 | +group :mysql do | ||
14 | + gem 'mysql', '~> 2.9' | ||
15 | + gem 'mysql2', '~> 0.3.10' | ||
16 | +end | ||
17 | +gem 'pg', '~> 0.11', :group => :pg | ||
18 | + | ||
19 | +group :development do | ||
20 | + gem 'ruby-debug', :platforms => :mri_18 | ||
21 | + gem 'debugger', :platforms => :mri_19 | ||
22 | +end |
@@ -0,0 +1,25 @@ | @@ -0,0 +1,25 @@ | ||
1 | +source 'https://rubygems.org' | ||
2 | + | ||
3 | +gem 'activerecord-deprecated_finders', :github => 'rails/activerecord-deprecated_finders', :branch => 'master' | ||
4 | +gem 'journey', :github => 'rails/journey', :branch => 'master' | ||
5 | + | ||
6 | +gem 'activerecord', :github => 'rails/rails', :branch => 'master' | ||
7 | +gem 'actionpack', :github => 'rails/rails', :branch => 'master' | ||
8 | + | ||
9 | +gem 'thread_safe' | ||
10 | + | ||
11 | +gem 'rspec', '~> 2.6.0' | ||
12 | +gem 'mocha', '~> 0.9.8' | ||
13 | + | ||
14 | +gem 'sqlite3', '~> 1.3.6' | ||
15 | + | ||
16 | +group :mysql do | ||
17 | + gem 'mysql', '~> 2.9' | ||
18 | + gem 'mysql2', '~> 0.3.10' | ||
19 | +end | ||
20 | +gem 'pg', '~> 0.11', :group => :pg | ||
21 | + | ||
22 | +group :development do | ||
23 | + gem 'ruby-debug', :platforms => :mri_18 | ||
24 | + gem 'debugger', :platforms => :mri_19 | ||
25 | +end |
@@ -0,0 +1,107 @@ | @@ -0,0 +1,107 @@ | ||
1 | +GIT | ||
2 | + remote: git://github.com/rails/activerecord-deprecated_finders.git | ||
3 | + revision: f6ed71d62d47f0f6397b5b3e801271567f30f960 | ||
4 | + branch: master | ||
5 | + specs: | ||
6 | + activerecord-deprecated_finders (1.0.3) | ||
7 | + | ||
8 | +GIT | ||
9 | + remote: git://github.com/rails/journey.git | ||
10 | + revision: f0938d664286dc0b47f13092fa5d04a9225038d4 | ||
11 | + branch: master | ||
12 | + specs: | ||
13 | + journey (2.0.0.20120723141804) | ||
14 | + | ||
15 | +GIT | ||
16 | + remote: git://github.com/rails/rails.git | ||
17 | + revision: 12fe66b56479abc2ca399c002d38a7e81fce2eb2 | ||
18 | + branch: master | ||
19 | + specs: | ||
20 | + actionpack (4.1.0.beta) | ||
21 | + actionview (= 4.1.0.beta) | ||
22 | + activesupport (= 4.1.0.beta) | ||
23 | + rack (~> 1.5.2) | ||
24 | + rack-test (~> 0.6.2) | ||
25 | + actionview (4.1.0.beta) | ||
26 | + activemodel (= 4.1.0.beta) | ||
27 | + activesupport (= 4.1.0.beta) | ||
28 | + builder (~> 3.1.0) | ||
29 | + erubis (~> 2.7.0) | ||
30 | + activemodel (4.1.0.beta) | ||
31 | + activesupport (= 4.1.0.beta) | ||
32 | + builder (~> 3.1.0) | ||
33 | + activerecord (4.1.0.beta) | ||
34 | + activemodel (= 4.1.0.beta) | ||
35 | + activerecord-deprecated_finders (~> 1.0.2) | ||
36 | + activesupport (= 4.1.0.beta) | ||
37 | + arel (~> 4.0.0) | ||
38 | + activesupport (4.1.0.beta) | ||
39 | + i18n (~> 0.6, >= 0.6.4) | ||
40 | + json (~> 1.7) | ||
41 | + minitest (~> 5.0) | ||
42 | + thread_safe (~> 0.1) | ||
43 | + tzinfo (~> 0.3.37) | ||
44 | + | ||
45 | +GEM | ||
46 | + remote: https://rubygems.org/ | ||
47 | + specs: | ||
48 | + arel (4.0.0) | ||
49 | + atomic (1.1.9) | ||
50 | + builder (3.1.4) | ||
51 | + columnize (0.3.6) | ||
52 | + debugger (1.6.0) | ||
53 | + columnize (>= 0.3.1) | ||
54 | + debugger-linecache (~> 1.2.0) | ||
55 | + debugger-ruby_core_source (~> 1.2.1) | ||
56 | + debugger-linecache (1.2.0) | ||
57 | + debugger-ruby_core_source (1.2.2) | ||
58 | + diff-lcs (1.1.3) | ||
59 | + erubis (2.7.0) | ||
60 | + i18n (0.6.4) | ||
61 | + json (1.8.0) | ||
62 | + linecache (0.46) | ||
63 | + rbx-require-relative (> 0.0.4) | ||
64 | + minitest (5.0.5) | ||
65 | + mocha (0.9.12) | ||
66 | + mysql (2.9.1) | ||
67 | + mysql2 (0.3.11) | ||
68 | + pg (0.15.1) | ||
69 | + rack (1.5.2) | ||
70 | + rack-test (0.6.2) | ||
71 | + rack (>= 1.0) | ||
72 | + rbx-require-relative (0.0.9) | ||
73 | + rspec (2.6.0) | ||
74 | + rspec-core (~> 2.6.0) | ||
75 | + rspec-expectations (~> 2.6.0) | ||
76 | + rspec-mocks (~> 2.6.0) | ||
77 | + rspec-core (2.6.4) | ||
78 | + rspec-expectations (2.6.0) | ||
79 | + diff-lcs (~> 1.1.2) | ||
80 | + rspec-mocks (2.6.0) | ||
81 | + ruby-debug (0.10.4) | ||
82 | + columnize (>= 0.1) | ||
83 | + ruby-debug-base (~> 0.10.4.0) | ||
84 | + ruby-debug-base (0.10.4) | ||
85 | + linecache (>= 0.3) | ||
86 | + sqlite3 (1.3.7) | ||
87 | + thread_safe (0.1.0) | ||
88 | + atomic | ||
89 | + tzinfo (0.3.37) | ||
90 | + | ||
91 | +PLATFORMS | ||
92 | + ruby | ||
93 | + | ||
94 | +DEPENDENCIES | ||
95 | + actionpack! | ||
96 | + activerecord! | ||
97 | + activerecord-deprecated_finders! | ||
98 | + debugger | ||
99 | + journey! | ||
100 | + mocha (~> 0.9.8) | ||
101 | + mysql (~> 2.9) | ||
102 | + mysql2 (~> 0.3.10) | ||
103 | + pg (~> 0.11) | ||
104 | + rspec (~> 2.6.0) | ||
105 | + ruby-debug | ||
106 | + sqlite3 (~> 1.3.6) | ||
107 | + thread_safe |
@@ -0,0 +1,19 @@ | @@ -0,0 +1,19 @@ | ||
1 | +source 'http://rubygems.org' | ||
2 | + | ||
3 | +rails_version = '~> 3.0.0' | ||
4 | + | ||
5 | +gem 'activerecord', rails_version | ||
6 | +gem 'actionpack', rails_version | ||
7 | + | ||
8 | +gem 'rspec', '~> 2.6.0' | ||
9 | +gem 'mocha', '~> 0.9.8' | ||
10 | + | ||
11 | +gem 'sqlite3', '~> 1.3.3' | ||
12 | + | ||
13 | +gem 'mysql', '~> 2.8.1', :group => :mysql | ||
14 | +gem 'pg', '~> 0.11', :group => :pg | ||
15 | + | ||
16 | +group :development do | ||
17 | + gem 'ruby-debug', :platforms => :mri_18 | ||
18 | + gem 'debugger', :platforms => :mri_19 | ||
19 | +end |
@@ -0,0 +1,78 @@ | @@ -0,0 +1,78 @@ | ||
1 | +GEM | ||
2 | + remote: http://rubygems.org/ | ||
3 | + specs: | ||
4 | + abstract (1.0.0) | ||
5 | + actionpack (3.0.19) | ||
6 | + activemodel (= 3.0.19) | ||
7 | + activesupport (= 3.0.19) | ||
8 | + builder (~> 2.1.2) | ||
9 | + erubis (~> 2.6.6) | ||
10 | + i18n (~> 0.5.0) | ||
11 | + rack (~> 1.2.5) | ||
12 | + rack-mount (~> 0.6.14) | ||
13 | + rack-test (~> 0.5.7) | ||
14 | + tzinfo (~> 0.3.23) | ||
15 | + activemodel (3.0.19) | ||
16 | + activesupport (= 3.0.19) | ||
17 | + builder (~> 2.1.2) | ||
18 | + i18n (~> 0.5.0) | ||
19 | + activerecord (3.0.19) | ||
20 | + activemodel (= 3.0.19) | ||
21 | + activesupport (= 3.0.19) | ||
22 | + arel (~> 2.0.10) | ||
23 | + tzinfo (~> 0.3.23) | ||
24 | + activesupport (3.0.19) | ||
25 | + arel (2.0.10) | ||
26 | + builder (2.1.2) | ||
27 | + columnize (0.3.4) | ||
28 | + debugger (1.2.2) | ||
29 | + columnize (>= 0.3.1) | ||
30 | + debugger-linecache (~> 1.1.1) | ||
31 | + debugger-ruby_core_source (~> 1.1.5) | ||
32 | + debugger-linecache (1.1.2) | ||
33 | + debugger-ruby_core_source (>= 1.1.1) | ||
34 | + debugger-ruby_core_source (1.1.5) | ||
35 | + diff-lcs (1.1.2) | ||
36 | + erubis (2.6.6) | ||
37 | + abstract (>= 1.0.0) | ||
38 | + i18n (0.5.0) | ||
39 | + linecache (0.46) | ||
40 | + rbx-require-relative (> 0.0.4) | ||
41 | + mocha (0.9.12) | ||
42 | + mysql (2.8.1) | ||
43 | + pg (0.11.0) | ||
44 | + rack (1.2.6) | ||
45 | + rack-mount (0.6.14) | ||
46 | + rack (>= 1.0.0) | ||
47 | + rack-test (0.5.7) | ||
48 | + rack (>= 1.0) | ||
49 | + rbx-require-relative (0.0.5) | ||
50 | + rspec (2.6.0) | ||
51 | + rspec-core (~> 2.6.0) | ||
52 | + rspec-expectations (~> 2.6.0) | ||
53 | + rspec-mocks (~> 2.6.0) | ||
54 | + rspec-core (2.6.4) | ||
55 | + rspec-expectations (2.6.0) | ||
56 | + diff-lcs (~> 1.1.2) | ||
57 | + rspec-mocks (2.6.0) | ||
58 | + ruby-debug (0.10.4) | ||
59 | + columnize (>= 0.1) | ||
60 | + ruby-debug-base (~> 0.10.4.0) | ||
61 | + ruby-debug-base (0.10.4) | ||
62 | + linecache (>= 0.3) | ||
63 | + sqlite3 (1.3.4) | ||
64 | + tzinfo (0.3.35) | ||
65 | + | ||
66 | +PLATFORMS | ||
67 | + ruby | ||
68 | + | ||
69 | +DEPENDENCIES | ||
70 | + actionpack (~> 3.0.0) | ||
71 | + activerecord (~> 3.0.0) | ||
72 | + debugger | ||
73 | + mocha (~> 0.9.8) | ||
74 | + mysql (~> 2.8.1) | ||
75 | + pg (~> 0.11) | ||
76 | + rspec (~> 2.6.0) | ||
77 | + ruby-debug | ||
78 | + sqlite3 (~> 1.3.3) |
@@ -0,0 +1,22 @@ | @@ -0,0 +1,22 @@ | ||
1 | +source 'http://rubygems.org' | ||
2 | + | ||
3 | +rails_version = '~> 3.1.0' | ||
4 | + | ||
5 | +gem 'activerecord', rails_version | ||
6 | +gem 'actionpack', rails_version | ||
7 | + | ||
8 | +gem 'rspec', '~> 2.6.0' | ||
9 | +gem 'mocha', '~> 0.9.8' | ||
10 | + | ||
11 | +gem 'sqlite3', '~> 1.3.3' | ||
12 | + | ||
13 | +group :mysql do | ||
14 | + gem 'mysql', '~> 2.8.1' | ||
15 | + gem 'mysql2', '>= 0.3.6' | ||
16 | +end | ||
17 | +gem 'pg', '~> 0.11', :group => :pg | ||
18 | + | ||
19 | +group :development do | ||
20 | + gem 'ruby-debug', :platforms => :mri_18 | ||
21 | + gem 'debugger', :platforms => :mri_19 | ||
22 | +end |
@@ -0,0 +1,93 @@ | @@ -0,0 +1,93 @@ | ||
1 | +GEM | ||
2 | + remote: http://rubygems.org/ | ||
3 | + specs: | ||
4 | + actionpack (3.1.12) | ||
5 | + activemodel (= 3.1.12) | ||
6 | + activesupport (= 3.1.12) | ||
7 | + builder (~> 3.0.0) | ||
8 | + erubis (~> 2.7.0) | ||
9 | + i18n (~> 0.6) | ||
10 | + rack (~> 1.3.6) | ||
11 | + rack-cache (~> 1.2) | ||
12 | + rack-mount (~> 0.8.2) | ||
13 | + rack-test (~> 0.6.1) | ||
14 | + sprockets (~> 2.0.4) | ||
15 | + activemodel (3.1.12) | ||
16 | + activesupport (= 3.1.12) | ||
17 | + builder (~> 3.0.0) | ||
18 | + i18n (~> 0.6) | ||
19 | + activerecord (3.1.12) | ||
20 | + activemodel (= 3.1.12) | ||
21 | + activesupport (= 3.1.12) | ||
22 | + arel (~> 2.2.3) | ||
23 | + tzinfo (~> 0.3.29) | ||
24 | + activesupport (3.1.12) | ||
25 | + multi_json (~> 1.0) | ||
26 | + arel (2.2.3) | ||
27 | + builder (3.0.4) | ||
28 | + columnize (0.3.6) | ||
29 | + debugger (1.2.2) | ||
30 | + columnize (>= 0.3.1) | ||
31 | + debugger-linecache (~> 1.1.1) | ||
32 | + debugger-ruby_core_source (~> 1.1.5) | ||
33 | + debugger-linecache (1.1.2) | ||
34 | + debugger-ruby_core_source (>= 1.1.1) | ||
35 | + debugger-ruby_core_source (1.1.5) | ||
36 | + diff-lcs (1.1.3) | ||
37 | + erubis (2.7.0) | ||
38 | + hike (1.2.3) | ||
39 | + i18n (0.6.4) | ||
40 | + linecache (0.46) | ||
41 | + rbx-require-relative (> 0.0.4) | ||
42 | + mocha (0.9.12) | ||
43 | + multi_json (1.7.7) | ||
44 | + mysql (2.8.1) | ||
45 | + mysql2 (0.3.11) | ||
46 | + pg (0.12.0) | ||
47 | + rake-compiler (~> 0.7) | ||
48 | + rack (1.3.10) | ||
49 | + rack-cache (1.2) | ||
50 | + rack (>= 0.4) | ||
51 | + rack-mount (0.8.3) | ||
52 | + rack (>= 1.0.0) | ||
53 | + rack-test (0.6.2) | ||
54 | + rack (>= 1.0) | ||
55 | + rake (0.9.2.2) | ||
56 | + rake-compiler (0.7.9) | ||
57 | + rake | ||
58 | + rbx-require-relative (0.0.5) | ||
59 | + rspec (2.6.0) | ||
60 | + rspec-core (~> 2.6.0) | ||
61 | + rspec-expectations (~> 2.6.0) | ||
62 | + rspec-mocks (~> 2.6.0) | ||
63 | + rspec-core (2.6.4) | ||
64 | + rspec-expectations (2.6.0) | ||
65 | + diff-lcs (~> 1.1.2) | ||
66 | + rspec-mocks (2.6.0) | ||
67 | + ruby-debug (0.10.4) | ||
68 | + columnize (>= 0.1) | ||
69 | + ruby-debug-base (~> 0.10.4.0) | ||
70 | + ruby-debug-base (0.10.4) | ||
71 | + linecache (>= 0.3) | ||
72 | + sprockets (2.0.4) | ||
73 | + hike (~> 1.2) | ||
74 | + rack (~> 1.0) | ||
75 | + tilt (~> 1.1, != 1.3.0) | ||
76 | + sqlite3 (1.3.5) | ||
77 | + tilt (1.4.1) | ||
78 | + tzinfo (0.3.37) | ||
79 | + | ||
80 | +PLATFORMS | ||
81 | + ruby | ||
82 | + | ||
83 | +DEPENDENCIES | ||
84 | + actionpack (~> 3.1.0) | ||
85 | + activerecord (~> 3.1.0) | ||
86 | + debugger | ||
87 | + mocha (~> 0.9.8) | ||
88 | + mysql (~> 2.8.1) | ||
89 | + mysql2 (>= 0.3.6) | ||
90 | + pg (~> 0.11) | ||
91 | + rspec (~> 2.6.0) | ||
92 | + ruby-debug | ||
93 | + sqlite3 (~> 1.3.3) |
@@ -0,0 +1,28 @@ | @@ -0,0 +1,28 @@ | ||
1 | +source 'http://rubygems.org' | ||
2 | + | ||
3 | +rails_version = '~> 3.2.0' | ||
4 | + | ||
5 | +gem 'activerecord', rails_version | ||
6 | +gem 'actionpack', rails_version | ||
7 | + | ||
8 | +gem 'rspec', '~> 2.6.0' | ||
9 | +gem 'mocha', '~> 0.9.8' | ||
10 | + | ||
11 | +gem 'sequel', '~> 3.8' | ||
12 | +gem 'sqlite3', '~> 1.3.3' | ||
13 | +gem 'dm-core' | ||
14 | +gem 'dm-aggregates' | ||
15 | +gem 'dm-migrations' | ||
16 | +gem 'dm-sqlite-adapter' | ||
17 | +gem 'mongoid' | ||
18 | + | ||
19 | +group :mysql do | ||
20 | + gem 'mysql', '~> 2.8.1' | ||
21 | + gem 'mysql2', '>= 0.3.6' | ||
22 | +end | ||
23 | +gem 'pg', '~> 0.11', :group => :pg | ||
24 | + | ||
25 | +group :development do | ||
26 | + gem 'ruby-debug', :platforms => :mri_18 | ||
27 | + gem 'debugger', :platforms => :mri_19 | ||
28 | +end |
@@ -0,0 +1,123 @@ | @@ -0,0 +1,123 @@ | ||
1 | +GEM | ||
2 | + remote: http://rubygems.org/ | ||
3 | + specs: | ||
4 | + actionpack (3.2.13) | ||
5 | + activemodel (= 3.2.13) | ||
6 | + activesupport (= 3.2.13) | ||
7 | + builder (~> 3.0.0) | ||
8 | + erubis (~> 2.7.0) | ||
9 | + journey (~> 1.0.4) | ||
10 | + rack (~> 1.4.5) | ||
11 | + rack-cache (~> 1.2) | ||
12 | + rack-test (~> 0.6.1) | ||
13 | + sprockets (~> 2.2.1) | ||
14 | + activemodel (3.2.13) | ||
15 | + activesupport (= 3.2.13) | ||
16 | + builder (~> 3.0.0) | ||
17 | + activerecord (3.2.13) | ||
18 | + activemodel (= 3.2.13) | ||
19 | + activesupport (= 3.2.13) | ||
20 | + arel (~> 3.0.2) | ||
21 | + tzinfo (~> 0.3.29) | ||
22 | + activesupport (3.2.13) | ||
23 | + i18n (= 0.6.1) | ||
24 | + multi_json (~> 1.0) | ||
25 | + addressable (2.2.6) | ||
26 | + arel (3.0.2) | ||
27 | + bson (1.6.4) | ||
28 | + builder (3.0.4) | ||
29 | + columnize (0.3.5) | ||
30 | + data_objects (0.10.7) | ||
31 | + addressable (~> 2.1) | ||
32 | + debugger (1.2.2) | ||
33 | + columnize (>= 0.3.1) | ||
34 | + debugger-linecache (~> 1.1.1) | ||
35 | + debugger-ruby_core_source (~> 1.1.5) | ||
36 | + debugger-linecache (1.1.2) | ||
37 | + debugger-ruby_core_source (>= 1.1.1) | ||
38 | + debugger-ruby_core_source (1.1.5) | ||
39 | + diff-lcs (1.1.3) | ||
40 | + dm-aggregates (1.2.0) | ||
41 | + dm-core (~> 1.2.0) | ||
42 | + dm-core (1.2.0) | ||
43 | + addressable (~> 2.2.6) | ||
44 | + dm-do-adapter (1.2.0) | ||
45 | + data_objects (~> 0.10.6) | ||
46 | + dm-core (~> 1.2.0) | ||
47 | + dm-migrations (1.2.0) | ||
48 | + dm-core (~> 1.2.0) | ||
49 | + dm-sqlite-adapter (1.2.0) | ||
50 | + dm-do-adapter (~> 1.2.0) | ||
51 | + do_sqlite3 (~> 0.10.6) | ||
52 | + do_sqlite3 (0.10.7) | ||
53 | + data_objects (= 0.10.7) | ||
54 | + erubis (2.7.0) | ||
55 | + hike (1.2.3) | ||
56 | + i18n (0.6.1) | ||
57 | + journey (1.0.4) | ||
58 | + linecache (0.46) | ||
59 | + rbx-require-relative (> 0.0.4) | ||
60 | + mocha (0.9.12) | ||
61 | + mongo (1.6.2) | ||
62 | + bson (~> 1.6.2) | ||
63 | + mongoid (2.4.11) | ||
64 | + activemodel (~> 3.1) | ||
65 | + mongo (<= 1.6.2) | ||
66 | + tzinfo (~> 0.3.22) | ||
67 | + multi_json (1.7.7) | ||
68 | + mysql (2.8.1) | ||
69 | + mysql2 (0.3.11) | ||
70 | + pg (0.12.0) | ||
71 | + rake-compiler (~> 0.7) | ||
72 | + rack (1.4.5) | ||
73 | + rack-cache (1.2) | ||
74 | + rack (>= 0.4) | ||
75 | + rack-test (0.6.2) | ||
76 | + rack (>= 1.0) | ||
77 | + rake (0.9.2.2) | ||
78 | + rake-compiler (0.7.9) | ||
79 | + rake | ||
80 | + rbx-require-relative (0.0.5) | ||
81 | + rspec (2.6.0) | ||
82 | + rspec-core (~> 2.6.0) | ||
83 | + rspec-expectations (~> 2.6.0) | ||
84 | + rspec-mocks (~> 2.6.0) | ||
85 | + rspec-core (2.6.4) | ||
86 | + rspec-expectations (2.6.0) | ||
87 | + diff-lcs (~> 1.1.2) | ||
88 | + rspec-mocks (2.6.0) | ||
89 | + ruby-debug (0.10.4) | ||
90 | + columnize (>= 0.1) | ||
91 | + ruby-debug-base (~> 0.10.4.0) | ||
92 | + ruby-debug-base (0.10.4) | ||
93 | + linecache (>= 0.3) | ||
94 | + sequel (3.30.0) | ||
95 | + sprockets (2.2.2) | ||
96 | + hike (~> 1.2) | ||
97 | + multi_json (~> 1.0) | ||
98 | + rack (~> 1.0) | ||
99 | + tilt (~> 1.1, != 1.3.0) | ||
100 | + sqlite3 (1.3.5) | ||
101 | + tilt (1.4.1) | ||
102 | + tzinfo (0.3.37) | ||
103 | + | ||
104 | +PLATFORMS | ||
105 | + ruby | ||
106 | + | ||
107 | +DEPENDENCIES | ||
108 | + actionpack (~> 3.2.0) | ||
109 | + activerecord (~> 3.2.0) | ||
110 | + debugger | ||
111 | + dm-aggregates | ||
112 | + dm-core | ||
113 | + dm-migrations | ||
114 | + dm-sqlite-adapter | ||
115 | + mocha (~> 0.9.8) | ||
116 | + mongoid | ||
117 | + mysql (~> 2.8.1) | ||
118 | + mysql2 (>= 0.3.6) | ||
119 | + pg (~> 0.11) | ||
120 | + rspec (~> 2.6.0) | ||
121 | + ruby-debug | ||
122 | + sequel (~> 3.8) | ||
123 | + sqlite3 (~> 1.3.3) |
@@ -0,0 +1,18 @@ | @@ -0,0 +1,18 @@ | ||
1 | +Copyright (c) 2009 Mislav Marohnić | ||
2 | + | ||
3 | +Permission is hereby granted, free of charge, to any person obtaining a copy of | ||
4 | +this software and associated documentation files (the "Software"), to deal in | ||
5 | +the Software without restriction, including without limitation the rights to | ||
6 | +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of | ||
7 | +the Software, and to permit persons to whom the Software is furnished to do so, | ||
8 | +subject to the following conditions: | ||
9 | + | ||
10 | +The above copyright notice and this permission notice shall be included in all | ||
11 | +copies or substantial portions of the Software. | ||
12 | + | ||
13 | +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
14 | +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS | ||
15 | +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR | ||
16 | +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER | ||
17 | +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | ||
18 | +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
@@ -0,0 +1,61 @@ | @@ -0,0 +1,61 @@ | ||
1 | +# will_paginate | ||
2 | + | ||
3 | +will_paginate is a pagination library that integrates with Ruby on Rails, Sinatra, Merb, DataMapper and Sequel. | ||
4 | + | ||
5 | +Installation: | ||
6 | + | ||
7 | +``` ruby | ||
8 | +## Gemfile for Rails 3, Sinatra, and Merb | ||
9 | +gem 'will_paginate', '~> 3.0' | ||
10 | +``` | ||
11 | + | ||
12 | +See [installation instructions][install] on the wiki for more info. | ||
13 | + | ||
14 | + | ||
15 | +## Basic will_paginate use | ||
16 | + | ||
17 | +``` ruby | ||
18 | +## perform a paginated query: | ||
19 | +@posts = Post.paginate(:page => params[:page]) | ||
20 | + | ||
21 | +# or, use an explicit "per page" limit: | ||
22 | +Post.paginate(:page => params[:page], :per_page => 30) | ||
23 | + | ||
24 | +## render page links in the view: | ||
25 | +<%= will_paginate @posts %> | ||
26 | +``` | ||
27 | + | ||
28 | +And that's it! You're done. You just need to add some CSS styles to [make those pagination links prettier][css]. | ||
29 | + | ||
30 | +You can customize the default "per_page" value: | ||
31 | + | ||
32 | +``` ruby | ||
33 | +# for the Post model | ||
34 | +class Post | ||
35 | + self.per_page = 10 | ||
36 | +end | ||
37 | + | ||
38 | +# set per_page globally | ||
39 | +WillPaginate.per_page = 10 | ||
40 | +``` | ||
41 | + | ||
42 | +New in Active Record 3: | ||
43 | + | ||
44 | +``` ruby | ||
45 | +# paginate in Active Record now returns a Relation | ||
46 | +Post.where(:published => true).paginate(:page => params[:page]).order('id DESC') | ||
47 | + | ||
48 | +# the new, shorter page() method | ||
49 | +Post.page(params[:page]).order('created_at DESC') | ||
50 | +``` | ||
51 | + | ||
52 | +See [the wiki][wiki] for more documentation. [Ask on the group][group] if you have usage questions. [Report bugs][issues] on GitHub. | ||
53 | + | ||
54 | +Happy paginating. | ||
55 | + | ||
56 | + | ||
57 | +[wiki]: https://github.com/mislav/will_paginate/wiki | ||
58 | +[install]: https://github.com/mislav/will_paginate/wiki/Installation "will_paginate installation" | ||
59 | +[group]: http://groups.google.com/group/will_paginate "will_paginate discussion and support group" | ||
60 | +[issues]: https://github.com/mislav/will_paginate/issues | ||
61 | +[css]: http://mislav.uniqpath.com/will_paginate/ |
@@ -0,0 +1,18 @@ | @@ -0,0 +1,18 @@ | ||
1 | +require 'will_paginate' | ||
2 | + | ||
3 | +# This is all duplication of what Railtie does, but is necessary because | ||
4 | +# the initializer defined by the Railtie won't ever run when loaded as plugin. | ||
5 | + | ||
6 | +if defined? ActiveRecord::Base | ||
7 | + require 'will_paginate/active_record' | ||
8 | +end | ||
9 | + | ||
10 | +if defined? ActionController::Base | ||
11 | + WillPaginate::Railtie.setup_actioncontroller | ||
12 | +end | ||
13 | + | ||
14 | +if defined? ActionView::Base | ||
15 | + require 'will_paginate/view_helpers/action_view' | ||
16 | +end | ||
17 | + | ||
18 | +WillPaginate::Railtie.add_locale_path config |
@@ -0,0 +1,25 @@ | @@ -0,0 +1,25 @@ | ||
1 | +# You will paginate! | ||
2 | +module WillPaginate | ||
3 | +end | ||
4 | + | ||
5 | +if defined?(Rails::Railtie) | ||
6 | + require 'will_paginate/railtie' | ||
7 | +elsif defined?(Rails::Initializer) | ||
8 | + raise "will_paginate 3.0 is not compatible with Rails 2.3 or older" | ||
9 | +end | ||
10 | + | ||
11 | +if defined?(Merb::AbstractController) | ||
12 | + require 'will_paginate/view_helpers/merb' | ||
13 | + | ||
14 | + Merb::BootLoader.before_app_loads do | ||
15 | + adapters = { :datamapper => 'data_mapper', :activerecord => 'active_record', :sequel => 'sequel' } | ||
16 | + # auto-load the right ORM adapter | ||
17 | + if adapter = adapters[Merb.orm] | ||
18 | + require "will_paginate/#{adapter}" | ||
19 | + end | ||
20 | + end | ||
21 | +end | ||
22 | + | ||
23 | +if defined?(Sinatra) and Sinatra.respond_to? :register | ||
24 | + require 'will_paginate/view_helpers/sinatra' | ||
25 | +end |
vendor/plugins/will_paginate/lib/will_paginate/active_record.rb
0 → 100644
@@ -0,0 +1,247 @@ | @@ -0,0 +1,247 @@ | ||
1 | +require 'will_paginate/per_page' | ||
2 | +require 'will_paginate/page_number' | ||
3 | +require 'will_paginate/collection' | ||
4 | +require 'active_record' | ||
5 | + | ||
6 | +module WillPaginate | ||
7 | + # = Paginating finders for ActiveRecord models | ||
8 | + # | ||
9 | + # WillPaginate adds +paginate+, +per_page+ and other methods to | ||
10 | + # ActiveRecord::Base class methods and associations. | ||
11 | + # | ||
12 | + # In short, paginating finders are equivalent to ActiveRecord finders; the | ||
13 | + # only difference is that we start with "paginate" instead of "find" and | ||
14 | + # that <tt>:page</tt> is required parameter: | ||
15 | + # | ||
16 | + # @posts = Post.paginate :all, :page => params[:page], :order => 'created_at DESC' | ||
17 | + # | ||
18 | + module ActiveRecord | ||
19 | + # makes a Relation look like WillPaginate::Collection | ||
20 | + module RelationMethods | ||
21 | + include WillPaginate::CollectionMethods | ||
22 | + | ||
23 | + attr_accessor :current_page | ||
24 | + attr_writer :total_entries, :wp_count_options | ||
25 | + | ||
26 | + def per_page(value = nil) | ||
27 | + if value.nil? then limit_value | ||
28 | + else limit(value) | ||
29 | + end | ||
30 | + end | ||
31 | + | ||
32 | + # TODO: solve with less relation clones and code dups | ||
33 | + def limit(num) | ||
34 | + rel = super | ||
35 | + if rel.current_page | ||
36 | + rel.offset rel.current_page.to_offset(rel.limit_value).to_i | ||
37 | + else | ||
38 | + rel | ||
39 | + end | ||
40 | + end | ||
41 | + | ||
42 | + # dirty hack to enable `first` after `limit` behavior above | ||
43 | + def first(*args) | ||
44 | + if current_page | ||
45 | + rel = clone | ||
46 | + rel.current_page = nil | ||
47 | + rel.first(*args) | ||
48 | + else | ||
49 | + super | ||
50 | + end | ||
51 | + end | ||
52 | + | ||
53 | + # fix for Rails 3.0 | ||
54 | + def find_last | ||
55 | + if !loaded? and offset_value || limit_value | ||
56 | + @last ||= to_a.last | ||
57 | + else | ||
58 | + super | ||
59 | + end | ||
60 | + end | ||
61 | + | ||
62 | + def offset(value = nil) | ||
63 | + if value.nil? then offset_value | ||
64 | + else super(value) | ||
65 | + end | ||
66 | + end | ||
67 | + | ||
68 | + def total_entries | ||
69 | + @total_entries ||= begin | ||
70 | + if loaded? and size < limit_value and (current_page == 1 or size > 0) | ||
71 | + offset_value + size | ||
72 | + else | ||
73 | + @total_entries_queried = true | ||
74 | + result = count | ||
75 | + result = result.size if result.respond_to?(:size) and !result.is_a?(Integer) | ||
76 | + result | ||
77 | + end | ||
78 | + end | ||
79 | + end | ||
80 | + | ||
81 | + def count | ||
82 | + if limit_value | ||
83 | + excluded = [:order, :limit, :offset, :reorder] | ||
84 | + excluded << :includes unless eager_loading? | ||
85 | + rel = self.except(*excluded) | ||
86 | + # TODO: hack. decide whether to keep | ||
87 | + rel = rel.apply_finder_options(@wp_count_options) if defined? @wp_count_options | ||
88 | + rel.count | ||
89 | + else | ||
90 | + super | ||
91 | + end | ||
92 | + end | ||
93 | + | ||
94 | + # workaround for Active Record 3.0 | ||
95 | + def size | ||
96 | + if !loaded? and limit_value and group_values.empty? | ||
97 | + [super, limit_value].min | ||
98 | + else | ||
99 | + super | ||
100 | + end | ||
101 | + end | ||
102 | + | ||
103 | + # overloaded to be pagination-aware | ||
104 | + def empty? | ||
105 | + if !loaded? and offset_value | ||
106 | + result = count | ||
107 | + result = result.size if result.respond_to?(:size) and !result.is_a?(Integer) | ||
108 | + result <= offset_value | ||
109 | + else | ||
110 | + super | ||
111 | + end | ||
112 | + end | ||
113 | + | ||
114 | + def clone | ||
115 | + copy_will_paginate_data super | ||
116 | + end | ||
117 | + | ||
118 | + # workaround for Active Record 3.0 | ||
119 | + def scoped(options = nil) | ||
120 | + copy_will_paginate_data super | ||
121 | + end | ||
122 | + | ||
123 | + def to_a | ||
124 | + if current_page.nil? then super # workaround for Active Record 3.0 | ||
125 | + else | ||
126 | + ::WillPaginate::Collection.create(current_page, limit_value) do |col| | ||
127 | + col.replace super | ||
128 | + col.total_entries ||= total_entries | ||
129 | + end | ||
130 | + end | ||
131 | + end | ||
132 | + | ||
133 | + private | ||
134 | + | ||
135 | + def copy_will_paginate_data(other) | ||
136 | + other.current_page = current_page unless other.current_page | ||
137 | + other.total_entries = nil if defined? @total_entries_queried | ||
138 | + other.wp_count_options = @wp_count_options if defined? @wp_count_options | ||
139 | + other | ||
140 | + end | ||
141 | + end | ||
142 | + | ||
143 | + module Pagination | ||
144 | + def paginate(options) | ||
145 | + options = options.dup | ||
146 | + pagenum = options.fetch(:page) { raise ArgumentError, ":page parameter required" } | ||
147 | + per_page = options.delete(:per_page) || self.per_page | ||
148 | + total = options.delete(:total_entries) | ||
149 | + | ||
150 | + count_options = options.delete(:count) | ||
151 | + options.delete(:page) | ||
152 | + | ||
153 | + rel = limit(per_page.to_i).page(pagenum) | ||
154 | + rel = rel.apply_finder_options(options) if options.any? | ||
155 | + rel.wp_count_options = count_options if count_options | ||
156 | + rel.total_entries = total.to_i unless total.blank? | ||
157 | + rel | ||
158 | + end | ||
159 | + | ||
160 | + def page(num) | ||
161 | + rel = if ::ActiveRecord::Relation === self | ||
162 | + self | ||
163 | + elsif !defined?(::ActiveRecord::Scoping) or ::ActiveRecord::Scoping::ClassMethods.method_defined? :with_scope | ||
164 | + # Active Record 3 | ||
165 | + scoped | ||
166 | + else | ||
167 | + # Active Record 4 | ||
168 | + all | ||
169 | + end | ||
170 | + | ||
171 | + rel = rel.extending(RelationMethods) | ||
172 | + pagenum = ::WillPaginate::PageNumber(num.nil? ? 1 : num) | ||
173 | + per_page = rel.limit_value || self.per_page | ||
174 | + rel = rel.offset(pagenum.to_offset(per_page).to_i) | ||
175 | + rel = rel.limit(per_page) unless rel.limit_value | ||
176 | + rel.current_page = pagenum | ||
177 | + rel | ||
178 | + end | ||
179 | + end | ||
180 | + | ||
181 | + module BaseMethods | ||
182 | + # Wraps +find_by_sql+ by simply adding LIMIT and OFFSET to your SQL string | ||
183 | + # based on the params otherwise used by paginating finds: +page+ and | ||
184 | + # +per_page+. | ||
185 | + # | ||
186 | + # Example: | ||
187 | + # | ||
188 | + # @developers = Developer.paginate_by_sql ['select * from developers where salary > ?', 80000], | ||
189 | + # :page => params[:page], :per_page => 3 | ||
190 | + # | ||
191 | + # A query for counting rows will automatically be generated if you don't | ||
192 | + # supply <tt>:total_entries</tt>. If you experience problems with this | ||
193 | + # generated SQL, you might want to perform the count manually in your | ||
194 | + # application. | ||
195 | + # | ||
196 | + def paginate_by_sql(sql, options) | ||
197 | + pagenum = options.fetch(:page) { raise ArgumentError, ":page parameter required" } || 1 | ||
198 | + per_page = options[:per_page] || self.per_page | ||
199 | + total = options[:total_entries] | ||
200 | + | ||
201 | + WillPaginate::Collection.create(pagenum, per_page, total) do |pager| | ||
202 | + query = sanitize_sql(sql.dup) | ||
203 | + original_query = query.dup | ||
204 | + oracle = self.connection.adapter_name =~ /^(oracle|oci$)/i | ||
205 | + | ||
206 | + # add limit, offset | ||
207 | + if oracle | ||
208 | + query = <<-SQL | ||
209 | + SELECT * FROM ( | ||
210 | + SELECT rownum rnum, a.* FROM (#{query}) a | ||
211 | + WHERE rownum <= #{pager.offset + pager.per_page} | ||
212 | + ) WHERE rnum >= #{pager.offset} | ||
213 | + SQL | ||
214 | + else | ||
215 | + query << " LIMIT #{pager.per_page} OFFSET #{pager.offset}" | ||
216 | + end | ||
217 | + | ||
218 | + # perfom the find | ||
219 | + pager.replace find_by_sql(query) | ||
220 | + | ||
221 | + unless pager.total_entries | ||
222 | + count_query = original_query.sub /\bORDER\s+BY\s+[\w`,\s.]+$/mi, '' | ||
223 | + count_query = "SELECT COUNT(*) FROM (#{count_query})" | ||
224 | + count_query << ' AS count_table' unless oracle | ||
225 | + # perform the count query | ||
226 | + pager.total_entries = count_by_sql(count_query) | ||
227 | + end | ||
228 | + end | ||
229 | + end | ||
230 | + end | ||
231 | + | ||
232 | + # mix everything into Active Record | ||
233 | + ::ActiveRecord::Base.extend PerPage | ||
234 | + ::ActiveRecord::Base.extend Pagination | ||
235 | + ::ActiveRecord::Base.extend BaseMethods | ||
236 | + | ||
237 | + klasses = [::ActiveRecord::Relation] | ||
238 | + if defined? ::ActiveRecord::Associations::CollectionProxy | ||
239 | + klasses << ::ActiveRecord::Associations::CollectionProxy | ||
240 | + else | ||
241 | + klasses << ::ActiveRecord::Associations::AssociationCollection | ||
242 | + end | ||
243 | + | ||
244 | + # support pagination on associations and scopes | ||
245 | + klasses.each { |klass| klass.send(:include, Pagination) } | ||
246 | + end | ||
247 | +end |
@@ -0,0 +1,33 @@ | @@ -0,0 +1,33 @@ | ||
1 | +require 'will_paginate/collection' | ||
2 | + | ||
3 | +class Array | ||
4 | + # Paginates a static array (extracting a subset of it). The result is a | ||
5 | + # WillPaginate::Collection instance, which is an array with a few more | ||
6 | + # properties about its paginated state. | ||
7 | + # | ||
8 | + # Parameters: | ||
9 | + # * <tt>:page</tt> - current page, defaults to 1 | ||
10 | + # * <tt>:per_page</tt> - limit of items per page, defaults to 30 | ||
11 | + # * <tt>:total_entries</tt> - total number of items in the array, defaults to | ||
12 | + # <tt>array.length</tt> (obviously) | ||
13 | + # | ||
14 | + # Example: | ||
15 | + # arr = ['a', 'b', 'c', 'd', 'e'] | ||
16 | + # paged = arr.paginate(:per_page => 2) #-> ['a', 'b'] | ||
17 | + # paged.total_entries #-> 5 | ||
18 | + # arr.paginate(:page => 2, :per_page => 2) #-> ['c', 'd'] | ||
19 | + # arr.paginate(:page => 3, :per_page => 2) #-> ['e'] | ||
20 | + # | ||
21 | + # This method was originally {suggested by Desi | ||
22 | + # McAdam}[http://www.desimcadam.com/archives/8] and later proved to be the | ||
23 | + # most useful method of will_paginate library. | ||
24 | + def paginate(options = {}) | ||
25 | + page = options[:page] || 1 | ||
26 | + per_page = options[:per_page] || WillPaginate.per_page | ||
27 | + total = options[:total_entries] || self.length | ||
28 | + | ||
29 | + WillPaginate::Collection.create(page, per_page, total) do |pager| | ||
30 | + pager.replace self[pager.offset, pager.per_page].to_a | ||
31 | + end | ||
32 | + end | ||
33 | +end |
vendor/plugins/will_paginate/lib/will_paginate/collection.rb
0 → 100644
@@ -0,0 +1,136 @@ | @@ -0,0 +1,136 @@ | ||
1 | +require 'will_paginate/per_page' | ||
2 | +require 'will_paginate/page_number' | ||
3 | + | ||
4 | +module WillPaginate | ||
5 | + # Any will_paginate-compatible collection should have these methods: | ||
6 | + # | ||
7 | + # current_page, per_page, offset, total_entries, total_pages | ||
8 | + # | ||
9 | + # It can also define some of these optional methods: | ||
10 | + # | ||
11 | + # out_of_bounds?, previous_page, next_page | ||
12 | + # | ||
13 | + # This module provides few of these methods. | ||
14 | + module CollectionMethods | ||
15 | + def total_pages | ||
16 | + total_entries.zero? ? 1 : (total_entries / per_page.to_f).ceil | ||
17 | + end | ||
18 | + | ||
19 | + # current_page - 1 or nil if there is no previous page | ||
20 | + def previous_page | ||
21 | + current_page > 1 ? (current_page - 1) : nil | ||
22 | + end | ||
23 | + | ||
24 | + # current_page + 1 or nil if there is no next page | ||
25 | + def next_page | ||
26 | + current_page < total_pages ? (current_page + 1) : nil | ||
27 | + end | ||
28 | + | ||
29 | + # Helper method that is true when someone tries to fetch a page with a | ||
30 | + # larger number than the last page. Can be used in combination with flashes | ||
31 | + # and redirecting. | ||
32 | + def out_of_bounds? | ||
33 | + current_page > total_pages | ||
34 | + end | ||
35 | + end | ||
36 | + | ||
37 | + # = The key to pagination | ||
38 | + # Arrays returned from paginating finds are, in fact, instances of this little | ||
39 | + # class. You may think of WillPaginate::Collection as an ordinary array with | ||
40 | + # some extra properties. Those properties are used by view helpers to generate | ||
41 | + # correct page links. | ||
42 | + # | ||
43 | + # WillPaginate::Collection also assists in rolling out your own pagination | ||
44 | + # solutions: see +create+. | ||
45 | + # | ||
46 | + # If you are writing a library that provides a collection which you would like | ||
47 | + # to conform to this API, you don't have to copy these methods over; simply | ||
48 | + # make your plugin/gem dependant on this library and do: | ||
49 | + # | ||
50 | + # require 'will_paginate/collection' | ||
51 | + # # WillPaginate::Collection is now available for use | ||
52 | + class Collection < Array | ||
53 | + include CollectionMethods | ||
54 | + | ||
55 | + attr_reader :current_page, :per_page, :total_entries | ||
56 | + | ||
57 | + # Arguments to the constructor are the current page number, per-page limit | ||
58 | + # and the total number of entries. The last argument is optional because it | ||
59 | + # is best to do lazy counting; in other words, count *conditionally* after | ||
60 | + # populating the collection using the +replace+ method. | ||
61 | + def initialize(page, per_page = WillPaginate.per_page, total = nil) | ||
62 | + @current_page = WillPaginate::PageNumber(page) | ||
63 | + @per_page = per_page.to_i | ||
64 | + self.total_entries = total if total | ||
65 | + end | ||
66 | + | ||
67 | + # Just like +new+, but yields the object after instantiation and returns it | ||
68 | + # afterwards. This is very useful for manual pagination: | ||
69 | + # | ||
70 | + # @entries = WillPaginate::Collection.create(1, 10) do |pager| | ||
71 | + # result = Post.find(:all, :limit => pager.per_page, :offset => pager.offset) | ||
72 | + # # inject the result array into the paginated collection: | ||
73 | + # pager.replace(result) | ||
74 | + # | ||
75 | + # unless pager.total_entries | ||
76 | + # # the pager didn't manage to guess the total count, do it manually | ||
77 | + # pager.total_entries = Post.count | ||
78 | + # end | ||
79 | + # end | ||
80 | + # | ||
81 | + # The possibilities with this are endless. For another example, here is how | ||
82 | + # WillPaginate used to define pagination for Array instances: | ||
83 | + # | ||
84 | + # Array.class_eval do | ||
85 | + # def paginate(page = 1, per_page = 15) | ||
86 | + # WillPaginate::Collection.create(page, per_page, size) do |pager| | ||
87 | + # pager.replace self[pager.offset, pager.per_page].to_a | ||
88 | + # end | ||
89 | + # end | ||
90 | + # end | ||
91 | + # | ||
92 | + # The Array#paginate API has since then changed, but this still serves as a | ||
93 | + # fine example of WillPaginate::Collection usage. | ||
94 | + def self.create(page, per_page, total = nil) | ||
95 | + pager = new(page, per_page, total) | ||
96 | + yield pager | ||
97 | + pager | ||
98 | + end | ||
99 | + | ||
100 | + # Current offset of the paginated collection. If we're on the first page, | ||
101 | + # it is always 0. If we're on the 2nd page and there are 30 entries per page, | ||
102 | + # the offset is 30. This property is useful if you want to render ordinals | ||
103 | + # side by side with records in the view: simply start with offset + 1. | ||
104 | + def offset | ||
105 | + current_page.to_offset(per_page).to_i | ||
106 | + end | ||
107 | + | ||
108 | + def total_entries=(number) | ||
109 | + @total_entries = number.to_i | ||
110 | + end | ||
111 | + | ||
112 | + # This is a magic wrapper for the original Array#replace method. It serves | ||
113 | + # for populating the paginated collection after initialization. | ||
114 | + # | ||
115 | + # Why magic? Because it tries to guess the total number of entries judging | ||
116 | + # by the size of given array. If it is shorter than +per_page+ limit, then we | ||
117 | + # know we're on the last page. This trick is very useful for avoiding | ||
118 | + # unnecessary hits to the database to do the counting after we fetched the | ||
119 | + # data for the current page. | ||
120 | + # | ||
121 | + # However, after using +replace+ you should always test the value of | ||
122 | + # +total_entries+ and set it to a proper value if it's +nil+. See the example | ||
123 | + # in +create+. | ||
124 | + def replace(array) | ||
125 | + result = super | ||
126 | + | ||
127 | + # The collection is shorter then page limit? Rejoice, because | ||
128 | + # then we know that we are on the last page! | ||
129 | + if total_entries.nil? and length < per_page and (current_page == 1 or length > 0) | ||
130 | + self.total_entries = offset + length | ||
131 | + end | ||
132 | + | ||
133 | + result | ||
134 | + end | ||
135 | + end | ||
136 | +end |
vendor/plugins/will_paginate/lib/will_paginate/core_ext.rb
0 → 100644
@@ -0,0 +1,30 @@ | @@ -0,0 +1,30 @@ | ||
1 | +require 'set' | ||
2 | + | ||
3 | +# copied from ActiveSupport so we don't depend on it | ||
4 | + | ||
5 | +unless Hash.method_defined? :except | ||
6 | + Hash.class_eval do | ||
7 | + # Returns a new hash without the given keys. | ||
8 | + def except(*keys) | ||
9 | + rejected = Set.new(respond_to?(:convert_key) ? keys.map { |key| convert_key(key) } : keys) | ||
10 | + reject { |key,| rejected.include?(key) } | ||
11 | + end | ||
12 | + | ||
13 | + # Replaces the hash without only the given keys. | ||
14 | + def except!(*keys) | ||
15 | + replace(except(*keys)) | ||
16 | + end | ||
17 | + end | ||
18 | +end | ||
19 | + | ||
20 | +unless String.method_defined? :underscore | ||
21 | + String.class_eval do | ||
22 | + def underscore | ||
23 | + self.to_s.gsub(/::/, '/'). | ||
24 | + gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2'). | ||
25 | + gsub(/([a-z\d])([A-Z])/,'\1_\2'). | ||
26 | + tr("-", "_"). | ||
27 | + downcase | ||
28 | + end | ||
29 | + end | ||
30 | +end |
vendor/plugins/will_paginate/lib/will_paginate/data_mapper.rb
0 → 100644
@@ -0,0 +1,95 @@ | @@ -0,0 +1,95 @@ | ||
1 | +require 'dm-core' | ||
2 | +require 'dm-aggregates' | ||
3 | +require 'will_paginate/per_page' | ||
4 | +require 'will_paginate/page_number' | ||
5 | +require 'will_paginate/collection' | ||
6 | + | ||
7 | +module WillPaginate | ||
8 | + module DataMapper | ||
9 | + module Pagination | ||
10 | + def page(num) | ||
11 | + pagenum = ::WillPaginate::PageNumber(num.nil? ? 1 : num) | ||
12 | + per_page = query.limit || self.per_page | ||
13 | + options = {:offset => pagenum.to_offset(per_page).to_i} | ||
14 | + options[:limit] = per_page unless query.limit | ||
15 | + col = new_collection(query.merge(options)) | ||
16 | + col.current_page = pagenum | ||
17 | + col | ||
18 | + end | ||
19 | + | ||
20 | + def paginate(options) | ||
21 | + options = options.dup | ||
22 | + pagenum = options.fetch(:page) { raise ArgumentError, ":page parameter required" } | ||
23 | + per_page = options.delete(:per_page) || self.per_page | ||
24 | + | ||
25 | + options.delete(:page) | ||
26 | + options[:limit] = per_page.to_i | ||
27 | + | ||
28 | + all(options).page(pagenum) | ||
29 | + end | ||
30 | + end | ||
31 | + | ||
32 | + module CollectionMethods | ||
33 | + include WillPaginate::CollectionMethods | ||
34 | + | ||
35 | + attr_accessor :current_page | ||
36 | + | ||
37 | + def paginated? | ||
38 | + !current_page.nil? | ||
39 | + end | ||
40 | + | ||
41 | + def per_page | ||
42 | + query.limit || model.per_page | ||
43 | + end | ||
44 | + | ||
45 | + def offset | ||
46 | + query.offset | ||
47 | + end | ||
48 | + | ||
49 | + def total_entries | ||
50 | + @total_entries ||= begin | ||
51 | + if loaded? and @array.size < per_page and (current_page == 1 or @array.size > 0) | ||
52 | + offset + @array.size | ||
53 | + else | ||
54 | + # :reload prevents Collection.filter from being run, which | ||
55 | + # would cause a stack overflow | ||
56 | + clean_query = query.merge(:reload => true) | ||
57 | + # seems like the only way | ||
58 | + clean_query.instance_variable_set('@limit', nil) | ||
59 | + clean_query.instance_variable_set('@offset', 0) | ||
60 | + new_collection(clean_query).count | ||
61 | + end | ||
62 | + end | ||
63 | + end | ||
64 | + | ||
65 | + def to_a | ||
66 | + if paginated? | ||
67 | + ::WillPaginate::Collection.create(current_page, per_page) do |col| | ||
68 | + col.replace super | ||
69 | + col.total_entries ||= total_entries | ||
70 | + end | ||
71 | + else | ||
72 | + super | ||
73 | + end | ||
74 | + end | ||
75 | + | ||
76 | + private | ||
77 | + | ||
78 | + def new_collection(query, resources = nil) | ||
79 | + col = super | ||
80 | + col.current_page = self.current_page | ||
81 | + col | ||
82 | + end | ||
83 | + | ||
84 | + def initialize_copy(original) | ||
85 | + super | ||
86 | + @total_entries = nil | ||
87 | + end | ||
88 | + end | ||
89 | + | ||
90 | + ::DataMapper::Model.append_extensions PerPage | ||
91 | + ::DataMapper::Model.append_extensions Pagination | ||
92 | + ::DataMapper::Collection.send(:include, Pagination) | ||
93 | + ::DataMapper::Collection.send(:include, CollectionMethods) | ||
94 | + end | ||
95 | +end |
vendor/plugins/will_paginate/lib/will_paginate/deprecation.rb
0 → 100644
@@ -0,0 +1,55 @@ | @@ -0,0 +1,55 @@ | ||
1 | +module WillPaginate::Deprecation | ||
2 | + class << self | ||
3 | + def warn(message, stack = caller) | ||
4 | + offending_line = origin_of_call(stack) | ||
5 | + full_message = "DEPRECATION WARNING: #{message} (called from #{offending_line})" | ||
6 | + logger = rails_logger || Kernel | ||
7 | + logger.warn full_message | ||
8 | + end | ||
9 | + | ||
10 | + private | ||
11 | + | ||
12 | + def rails_logger | ||
13 | + defined?(Rails) && Rails.logger | ||
14 | + end | ||
15 | + | ||
16 | + def origin_of_call(stack) | ||
17 | + lib_root = File.expand_path('../../..', __FILE__) | ||
18 | + stack.find { |line| line.index(lib_root) != 0 } || stack.first | ||
19 | + end | ||
20 | + end | ||
21 | + | ||
22 | + class Hash < ::Hash | ||
23 | + def initialize(values = {}) | ||
24 | + super() | ||
25 | + update values | ||
26 | + @deprecated = {} | ||
27 | + end | ||
28 | + | ||
29 | + def []=(key, value) | ||
30 | + check_deprecated(key, value) | ||
31 | + super | ||
32 | + end | ||
33 | + | ||
34 | + def deprecate_key(*keys) | ||
35 | + message = block_given? ? Proc.new : keys.pop | ||
36 | + Array(keys).each { |key| @deprecated[key] = message } | ||
37 | + end | ||
38 | + | ||
39 | + def merge(another) | ||
40 | + to_hash.update(another) | ||
41 | + end | ||
42 | + | ||
43 | + def to_hash | ||
44 | + ::Hash.new.update(self) | ||
45 | + end | ||
46 | + | ||
47 | + private | ||
48 | + | ||
49 | + def check_deprecated(key, value) | ||
50 | + if msg = @deprecated[key] and (!msg.respond_to?(:call) or (msg = msg.call(key, value))) | ||
51 | + WillPaginate::Deprecation.warn(msg) | ||
52 | + end | ||
53 | + end | ||
54 | + end | ||
55 | +end |
@@ -0,0 +1,22 @@ | @@ -0,0 +1,22 @@ | ||
1 | +module WillPaginate | ||
2 | + module I18n | ||
3 | + def self.locale_dir | ||
4 | + File.expand_path('../locale', __FILE__) | ||
5 | + end | ||
6 | + | ||
7 | + def self.load_path | ||
8 | + Dir["#{locale_dir}/*.{rb,yml}"] | ||
9 | + end | ||
10 | + | ||
11 | + def will_paginate_translate(keys, options = {}) | ||
12 | + if defined? ::I18n | ||
13 | + defaults = Array(keys).dup | ||
14 | + defaults << Proc.new if block_given? | ||
15 | + ::I18n.translate(defaults.shift, options.merge(:default => defaults, :scope => :will_paginate)) | ||
16 | + else | ||
17 | + key = Array === keys ? keys.first : keys | ||
18 | + yield key, options | ||
19 | + end | ||
20 | + end | ||
21 | + end | ||
22 | +end |
vendor/plugins/will_paginate/lib/will_paginate/mongoid.rb
0 → 100644
@@ -0,0 +1,46 @@ | @@ -0,0 +1,46 @@ | ||
1 | +require 'mongoid' | ||
2 | +require 'will_paginate/collection' | ||
3 | + | ||
4 | +module WillPaginate | ||
5 | + module Mongoid | ||
6 | + module CriteriaMethods | ||
7 | + def paginate(options = {}) | ||
8 | + extend CollectionMethods | ||
9 | + @current_page = WillPaginate::PageNumber(options[:page] || @current_page || 1) | ||
10 | + @page_multiplier = current_page - 1 | ||
11 | + pp = (options[:per_page] || per_page || WillPaginate.per_page).to_i | ||
12 | + limit(pp).skip(@page_multiplier * pp) | ||
13 | + end | ||
14 | + | ||
15 | + def per_page(value = :non_given) | ||
16 | + if value == :non_given | ||
17 | + options[:limit] == 0 ? nil : options[:limit] # in new Mongoid versions a nil limit is saved as 0 | ||
18 | + else | ||
19 | + limit(value) | ||
20 | + end | ||
21 | + end | ||
22 | + | ||
23 | + def page(page) | ||
24 | + paginate(:page => page) | ||
25 | + end | ||
26 | + end | ||
27 | + | ||
28 | + module CollectionMethods | ||
29 | + attr_reader :current_page | ||
30 | + | ||
31 | + def total_entries | ||
32 | + @total_entries ||= count | ||
33 | + end | ||
34 | + | ||
35 | + def total_pages | ||
36 | + (total_entries / per_page.to_f).ceil | ||
37 | + end | ||
38 | + | ||
39 | + def offset | ||
40 | + @page_multiplier * per_page | ||
41 | + end | ||
42 | + end | ||
43 | + | ||
44 | + ::Mongoid::Criteria.send(:include, CriteriaMethods) | ||
45 | + end | ||
46 | +end |
vendor/plugins/will_paginate/lib/will_paginate/page_number.rb
0 → 100644
@@ -0,0 +1,57 @@ | @@ -0,0 +1,57 @@ | ||
1 | +require 'delegate' | ||
2 | +require 'forwardable' | ||
3 | + | ||
4 | +module WillPaginate | ||
5 | + # a module that page number exceptions are tagged with | ||
6 | + module InvalidPage; end | ||
7 | + | ||
8 | + # integer representing a page number | ||
9 | + class PageNumber < DelegateClass(Integer) | ||
10 | + # a value larger than this is not supported in SQL queries | ||
11 | + BIGINT = 9223372036854775807 | ||
12 | + | ||
13 | + extend Forwardable | ||
14 | + | ||
15 | + def initialize(value, name) | ||
16 | + value = Integer(value) | ||
17 | + if 'offset' == name ? (value < 0 or value > BIGINT) : value < 1 | ||
18 | + raise RangeError, "invalid #{name}: #{value.inspect}" | ||
19 | + end | ||
20 | + @name = name | ||
21 | + super(value) | ||
22 | + rescue ArgumentError, TypeError, RangeError => error | ||
23 | + error.extend InvalidPage | ||
24 | + raise error | ||
25 | + end | ||
26 | + | ||
27 | + alias_method :to_i, :__getobj__ | ||
28 | + | ||
29 | + def inspect | ||
30 | + "#{@name} #{to_i}" | ||
31 | + end | ||
32 | + | ||
33 | + def to_offset(per_page) | ||
34 | + PageNumber.new((to_i - 1) * per_page.to_i, 'offset') | ||
35 | + end | ||
36 | + | ||
37 | + def kind_of?(klass) | ||
38 | + super || to_i.kind_of?(klass) | ||
39 | + end | ||
40 | + alias is_a? kind_of? | ||
41 | + end | ||
42 | + | ||
43 | + # Ultrahax: makes `Fixnum === current_page` checks pass | ||
44 | + Numeric.extend Module.new { | ||
45 | + def ===(obj) | ||
46 | + obj.instance_of? PageNumber or super | ||
47 | + end | ||
48 | + } | ||
49 | + | ||
50 | + # An idemptotent coercion method | ||
51 | + def self.PageNumber(value, name = 'page') | ||
52 | + case value | ||
53 | + when PageNumber then value | ||
54 | + else PageNumber.new(value, name) | ||
55 | + end | ||
56 | + end | ||
57 | +end |
vendor/plugins/will_paginate/lib/will_paginate/per_page.rb
0 → 100644
@@ -0,0 +1,27 @@ | @@ -0,0 +1,27 @@ | ||
1 | +module WillPaginate | ||
2 | + module PerPage | ||
3 | + def per_page | ||
4 | + defined?(@per_page) ? @per_page : WillPaginate.per_page | ||
5 | + end | ||
6 | + | ||
7 | + def per_page=(limit) | ||
8 | + @per_page = limit.to_i | ||
9 | + end | ||
10 | + | ||
11 | + def self.extended(base) | ||
12 | + base.extend Inheritance if base.is_a? Class | ||
13 | + end | ||
14 | + | ||
15 | + module Inheritance | ||
16 | + def inherited(subclass) | ||
17 | + super | ||
18 | + subclass.per_page = self.per_page | ||
19 | + end | ||
20 | + end | ||
21 | + end | ||
22 | + | ||
23 | + extend PerPage | ||
24 | + | ||
25 | + # default number of items per page | ||
26 | + self.per_page = 30 | ||
27 | +end |
vendor/plugins/will_paginate/lib/will_paginate/railtie.rb
0 → 100644
@@ -0,0 +1,68 @@ | @@ -0,0 +1,68 @@ | ||
1 | +require 'will_paginate' | ||
2 | +require 'will_paginate/page_number' | ||
3 | +require 'will_paginate/collection' | ||
4 | +require 'will_paginate/i18n' | ||
5 | + | ||
6 | +module WillPaginate | ||
7 | + class Railtie < Rails::Railtie | ||
8 | + initializer "will_paginate" do |app| | ||
9 | + ActiveSupport.on_load :active_record do | ||
10 | + require 'will_paginate/active_record' | ||
11 | + end | ||
12 | + | ||
13 | + ActiveSupport.on_load :action_controller do | ||
14 | + WillPaginate::Railtie.setup_actioncontroller | ||
15 | + end | ||
16 | + | ||
17 | + ActiveSupport.on_load :action_view do | ||
18 | + require 'will_paginate/view_helpers/action_view' | ||
19 | + end | ||
20 | + | ||
21 | + self.class.add_locale_path config | ||
22 | + | ||
23 | + # early access to ViewHelpers.pagination_options | ||
24 | + require 'will_paginate/view_helpers' | ||
25 | + end | ||
26 | + | ||
27 | + def self.setup_actioncontroller | ||
28 | + ( defined?(ActionDispatch::ExceptionWrapper) ? | ||
29 | + ActionDispatch::ExceptionWrapper : ActionDispatch::ShowExceptions | ||
30 | + ).send :include, ShowExceptionsPatch | ||
31 | + ActionController::Base.extend ControllerRescuePatch | ||
32 | + end | ||
33 | + | ||
34 | + def self.add_locale_path(config) | ||
35 | + config.i18n.railties_load_path.unshift(*WillPaginate::I18n.load_path) | ||
36 | + end | ||
37 | + | ||
38 | + # Extending the exception handler middleware so it properly detects | ||
39 | + # WillPaginate::InvalidPage regardless of it being a tag module. | ||
40 | + module ShowExceptionsPatch | ||
41 | + extend ActiveSupport::Concern | ||
42 | + included { alias_method_chain :status_code, :paginate } | ||
43 | + def status_code_with_paginate(exception = @exception) | ||
44 | + if exception.is_a?(WillPaginate::InvalidPage) or | ||
45 | + (exception.respond_to?(:original_exception) && | ||
46 | + exception.original_exception.is_a?(WillPaginate::InvalidPage)) | ||
47 | + Rack::Utils.status_code(:not_found) | ||
48 | + else | ||
49 | + original_method = method(:status_code_without_paginate) | ||
50 | + if original_method.arity != 0 | ||
51 | + original_method.call(exception) | ||
52 | + else | ||
53 | + original_method.call() | ||
54 | + end | ||
55 | + end | ||
56 | + end | ||
57 | + end | ||
58 | + | ||
59 | + module ControllerRescuePatch | ||
60 | + def rescue_from(*args, &block) | ||
61 | + if idx = args.index(WillPaginate::InvalidPage) | ||
62 | + args[idx] = args[idx].name | ||
63 | + end | ||
64 | + super(*args, &block) | ||
65 | + end | ||
66 | + end | ||
67 | + end | ||
68 | +end |
vendor/plugins/will_paginate/lib/will_paginate/sequel.rb
0 → 100644
@@ -0,0 +1,39 @@ | @@ -0,0 +1,39 @@ | ||
1 | +require 'sequel' | ||
2 | +require 'sequel/extensions/pagination' | ||
3 | +require 'will_paginate/collection' | ||
4 | + | ||
5 | +module WillPaginate | ||
6 | + # Sequel already supports pagination; we only need to make the | ||
7 | + # resulting dataset look a bit more like WillPaginate::Collection | ||
8 | + module SequelMethods | ||
9 | + include WillPaginate::CollectionMethods | ||
10 | + | ||
11 | + def total_pages | ||
12 | + page_count | ||
13 | + end | ||
14 | + | ||
15 | + def per_page | ||
16 | + page_size | ||
17 | + end | ||
18 | + | ||
19 | + def size | ||
20 | + current_page_record_count | ||
21 | + end | ||
22 | + alias length size | ||
23 | + | ||
24 | + def total_entries | ||
25 | + pagination_record_count | ||
26 | + end | ||
27 | + | ||
28 | + def out_of_bounds? | ||
29 | + current_page > total_pages | ||
30 | + end | ||
31 | + | ||
32 | + # Current offset of the paginated collection | ||
33 | + def offset | ||
34 | + (current_page - 1) * per_page | ||
35 | + end | ||
36 | + end | ||
37 | + | ||
38 | + Sequel::Dataset::Pagination.send(:include, SequelMethods) | ||
39 | +end |
vendor/plugins/will_paginate/lib/will_paginate/version.rb
0 → 100644
vendor/plugins/will_paginate/lib/will_paginate/view_helpers.rb
0 → 100644
@@ -0,0 +1,162 @@ | @@ -0,0 +1,162 @@ | ||
1 | +# encoding: utf-8 | ||
2 | +require 'will_paginate/core_ext' | ||
3 | +require 'will_paginate/i18n' | ||
4 | +require 'will_paginate/deprecation' | ||
5 | + | ||
6 | +module WillPaginate | ||
7 | + # = Will Paginate view helpers | ||
8 | + # | ||
9 | + # The main view helper is +will_paginate+. It renders the pagination links | ||
10 | + # for the given collection. The helper itself is lightweight and serves only | ||
11 | + # as a wrapper around LinkRenderer instantiation; the renderer then does | ||
12 | + # all the hard work of generating the HTML. | ||
13 | + module ViewHelpers | ||
14 | + class << self | ||
15 | + # Write to this hash to override default options on the global level: | ||
16 | + # | ||
17 | + # WillPaginate::ViewHelpers.pagination_options[:page_links] = false | ||
18 | + # | ||
19 | + attr_accessor :pagination_options | ||
20 | + end | ||
21 | + | ||
22 | + # default view options | ||
23 | + self.pagination_options = Deprecation::Hash.new \ | ||
24 | + :class => 'pagination', | ||
25 | + :previous_label => nil, | ||
26 | + :next_label => nil, | ||
27 | + :inner_window => 4, # links around the current page | ||
28 | + :outer_window => 1, # links around beginning and end | ||
29 | + :link_separator => ' ', # single space is friendly to spiders and non-graphic browsers | ||
30 | + :param_name => :page, | ||
31 | + :params => nil, | ||
32 | + :page_links => true, | ||
33 | + :container => true | ||
34 | + | ||
35 | + label_deprecation = Proc.new { |key, value| | ||
36 | + "set the 'will_paginate.#{key}' key in your i18n locale instead of editing pagination_options" if defined? Rails | ||
37 | + } | ||
38 | + pagination_options.deprecate_key(:previous_label, :next_label, &label_deprecation) | ||
39 | + pagination_options.deprecate_key(:renderer) { |key, _| "pagination_options[#{key.inspect}] shouldn't be set globally" } | ||
40 | + | ||
41 | + include WillPaginate::I18n | ||
42 | + | ||
43 | + # Returns HTML representing page links for a WillPaginate::Collection-like object. | ||
44 | + # In case there is no more than one page in total, nil is returned. | ||
45 | + # | ||
46 | + # ==== Options | ||
47 | + # * <tt>:class</tt> -- CSS class name for the generated DIV (default: "pagination") | ||
48 | + # * <tt>:previous_label</tt> -- default: "« Previous" | ||
49 | + # * <tt>:next_label</tt> -- default: "Next »" | ||
50 | + # * <tt>:inner_window</tt> -- how many links are shown around the current page (default: 4) | ||
51 | + # * <tt>:outer_window</tt> -- how many links are around the first and the last page (default: 1) | ||
52 | + # * <tt>:link_separator</tt> -- string separator for page HTML elements (default: single space) | ||
53 | + # * <tt>:param_name</tt> -- parameter name for page number in URLs (default: <tt>:page</tt>) | ||
54 | + # * <tt>:params</tt> -- additional parameters when generating pagination links | ||
55 | + # (eg. <tt>:controller => "foo", :action => nil</tt>) | ||
56 | + # * <tt>:renderer</tt> -- class name, class or instance of a link renderer (default in Rails: | ||
57 | + # <tt>WillPaginate::ActionView::LinkRenderer</tt>) | ||
58 | + # * <tt>:page_links</tt> -- when false, only previous/next links are rendered (default: true) | ||
59 | + # * <tt>:container</tt> -- toggles rendering of the DIV container for pagination links, set to | ||
60 | + # false only when you are rendering your own pagination markup (default: true) | ||
61 | + # | ||
62 | + # All options not recognized by will_paginate will become HTML attributes on the container | ||
63 | + # element for pagination links (the DIV). For example: | ||
64 | + # | ||
65 | + # <%= will_paginate @posts, :style => 'color:blue' %> | ||
66 | + # | ||
67 | + # will result in: | ||
68 | + # | ||
69 | + # <div class="pagination" style="color:blue"> ... </div> | ||
70 | + # | ||
71 | + def will_paginate(collection, options = {}) | ||
72 | + # early exit if there is nothing to render | ||
73 | + return nil unless collection.total_pages > 1 | ||
74 | + | ||
75 | + options = WillPaginate::ViewHelpers.pagination_options.merge(options) | ||
76 | + | ||
77 | + options[:previous_label] ||= will_paginate_translate(:previous_label) { '← Previous' } | ||
78 | + options[:next_label] ||= will_paginate_translate(:next_label) { 'Next →' } | ||
79 | + | ||
80 | + # get the renderer instance | ||
81 | + renderer = case options[:renderer] | ||
82 | + when nil | ||
83 | + raise ArgumentError, ":renderer not specified" | ||
84 | + when String | ||
85 | + klass = if options[:renderer].respond_to? :constantize then options[:renderer].constantize | ||
86 | + else Object.const_get(options[:renderer]) # poor man's constantize | ||
87 | + end | ||
88 | + klass.new | ||
89 | + when Class then options[:renderer].new | ||
90 | + else options[:renderer] | ||
91 | + end | ||
92 | + # render HTML for pagination | ||
93 | + renderer.prepare collection, options, self | ||
94 | + output = renderer.to_html | ||
95 | + output = output.html_safe if output.respond_to?(:html_safe) | ||
96 | + output | ||
97 | + end | ||
98 | + | ||
99 | + # Renders a message containing number of displayed vs. total entries. | ||
100 | + # | ||
101 | + # <%= page_entries_info @posts %> | ||
102 | + # #-> Displaying posts 6 - 12 of 26 in total | ||
103 | + # | ||
104 | + # The default output contains HTML. Use ":html => false" for plain text. | ||
105 | + def page_entries_info(collection, options = {}) | ||
106 | + model = options[:model] | ||
107 | + model = collection.first.class unless model or collection.empty? | ||
108 | + model ||= 'entry' | ||
109 | + model_key = if model.respond_to? :model_name | ||
110 | + model.model_name.i18n_key # ActiveModel::Naming | ||
111 | + else | ||
112 | + model.to_s.underscore | ||
113 | + end | ||
114 | + | ||
115 | + if options.fetch(:html, true) | ||
116 | + b, eb = '<b>', '</b>' | ||
117 | + sp = ' ' | ||
118 | + html_key = '_html' | ||
119 | + else | ||
120 | + b = eb = html_key = '' | ||
121 | + sp = ' ' | ||
122 | + end | ||
123 | + | ||
124 | + model_count = collection.total_pages > 1 ? 5 : collection.size | ||
125 | + defaults = ["models.#{model_key}"] | ||
126 | + defaults << Proc.new { |_, opts| | ||
127 | + if model.respond_to? :model_name | ||
128 | + model.model_name.human(:count => opts[:count]) | ||
129 | + else | ||
130 | + name = model_key.to_s.tr('_', ' ') | ||
131 | + raise "can't pluralize model name: #{model.inspect}" unless name.respond_to? :pluralize | ||
132 | + opts[:count] == 1 ? name : name.pluralize | ||
133 | + end | ||
134 | + } | ||
135 | + model_name = will_paginate_translate defaults, :count => model_count | ||
136 | + | ||
137 | + if collection.total_pages < 2 | ||
138 | + i18n_key = :"page_entries_info.single_page#{html_key}" | ||
139 | + keys = [:"#{model_key}.#{i18n_key}", i18n_key] | ||
140 | + | ||
141 | + will_paginate_translate keys, :count => collection.total_entries, :model => model_name do |_, opts| | ||
142 | + case opts[:count] | ||
143 | + when 0; "No #{opts[:model]} found" | ||
144 | + when 1; "Displaying #{b}1#{eb} #{opts[:model]}" | ||
145 | + else "Displaying #{b}all#{sp}#{opts[:count]}#{eb} #{opts[:model]}" | ||
146 | + end | ||
147 | + end | ||
148 | + else | ||
149 | + i18n_key = :"page_entries_info.multi_page#{html_key}" | ||
150 | + keys = [:"#{model_key}.#{i18n_key}", i18n_key] | ||
151 | + params = { | ||
152 | + :model => model_name, :count => collection.total_entries, | ||
153 | + :from => collection.offset + 1, :to => collection.offset + collection.length | ||
154 | + } | ||
155 | + will_paginate_translate keys, params do |_, opts| | ||
156 | + %{Displaying %s #{b}%d#{sp}-#{sp}%d#{eb} of #{b}%d#{eb} in total} % | ||
157 | + [ opts[:model], opts[:from], opts[:to], opts[:count] ] | ||
158 | + end | ||
159 | + end | ||
160 | + end | ||
161 | + end | ||
162 | +end |
vendor/plugins/will_paginate/lib/will_paginate/view_helpers/action_view.rb
0 → 100644
@@ -0,0 +1,148 @@ | @@ -0,0 +1,148 @@ | ||
1 | +require 'will_paginate/view_helpers' | ||
2 | +require 'will_paginate/view_helpers/link_renderer' | ||
3 | + | ||
4 | +module WillPaginate | ||
5 | + # = ActionView helpers | ||
6 | + # | ||
7 | + # This module serves for availability in ActionView templates. It also adds a new | ||
8 | + # view helper: +paginated_section+. | ||
9 | + # | ||
10 | + # == Using the helper without arguments | ||
11 | + # If the helper is called without passing in the collection object, it will | ||
12 | + # try to read from the instance variable inferred by the controller name. | ||
13 | + # For example, calling +will_paginate+ while the current controller is | ||
14 | + # PostsController will result in trying to read from the <tt>@posts</tt> | ||
15 | + # variable. Example: | ||
16 | + # | ||
17 | + # <%= will_paginate :id => true %> | ||
18 | + # | ||
19 | + # ... will result in <tt>@post</tt> collection getting paginated: | ||
20 | + # | ||
21 | + # <div class="pagination" id="posts_pagination"> ... </div> | ||
22 | + # | ||
23 | + module ActionView | ||
24 | + include ViewHelpers | ||
25 | + | ||
26 | + def will_paginate(collection = nil, options = {}) #:nodoc: | ||
27 | + options, collection = collection, nil if collection.is_a? Hash | ||
28 | + collection ||= infer_collection_from_controller | ||
29 | + | ||
30 | + options = options.symbolize_keys | ||
31 | + options[:renderer] ||= LinkRenderer | ||
32 | + | ||
33 | + super(collection, options) | ||
34 | + end | ||
35 | + | ||
36 | + def page_entries_info(collection = nil, options = {}) #:nodoc: | ||
37 | + options, collection = collection, nil if collection.is_a? Hash | ||
38 | + collection ||= infer_collection_from_controller | ||
39 | + | ||
40 | + super(collection, options.symbolize_keys) | ||
41 | + end | ||
42 | + | ||
43 | + # Wrapper for rendering pagination links at both top and bottom of a block | ||
44 | + # of content. | ||
45 | + # | ||
46 | + # <% paginated_section @posts do %> | ||
47 | + # <ol id="posts"> | ||
48 | + # <% for post in @posts %> | ||
49 | + # <li> ... </li> | ||
50 | + # <% end %> | ||
51 | + # </ol> | ||
52 | + # <% end %> | ||
53 | + # | ||
54 | + # will result in: | ||
55 | + # | ||
56 | + # <div class="pagination"> ... </div> | ||
57 | + # <ol id="posts"> | ||
58 | + # ... | ||
59 | + # </ol> | ||
60 | + # <div class="pagination"> ... </div> | ||
61 | + # | ||
62 | + # Arguments are passed to a <tt>will_paginate</tt> call, so the same options | ||
63 | + # apply. Don't use the <tt>:id</tt> option; otherwise you'll finish with two | ||
64 | + # blocks of pagination links sharing the same ID (which is invalid HTML). | ||
65 | + def paginated_section(*args, &block) | ||
66 | + pagination = will_paginate(*args) | ||
67 | + if pagination | ||
68 | + pagination + capture(&block) + pagination | ||
69 | + else | ||
70 | + capture(&block) | ||
71 | + end | ||
72 | + end | ||
73 | + | ||
74 | + def will_paginate_translate(keys, options = {}) | ||
75 | + if respond_to? :translate | ||
76 | + if Array === keys | ||
77 | + defaults = keys.dup | ||
78 | + key = defaults.shift | ||
79 | + else | ||
80 | + defaults = nil | ||
81 | + key = keys | ||
82 | + end | ||
83 | + translate(key, options.merge(:default => defaults, :scope => :will_paginate)) | ||
84 | + else | ||
85 | + super | ||
86 | + end | ||
87 | + end | ||
88 | + | ||
89 | + protected | ||
90 | + | ||
91 | + def infer_collection_from_controller | ||
92 | + collection_name = "@#{controller.controller_name}" | ||
93 | + collection = instance_variable_get(collection_name) | ||
94 | + raise ArgumentError, "The #{collection_name} variable appears to be empty. Did you " + | ||
95 | + "forget to pass the collection object for will_paginate?" if collection.nil? | ||
96 | + collection | ||
97 | + end | ||
98 | + | ||
99 | + class LinkRenderer < ViewHelpers::LinkRenderer | ||
100 | + protected | ||
101 | + | ||
102 | + def default_url_params | ||
103 | + {} | ||
104 | + end | ||
105 | + | ||
106 | + def url(page) | ||
107 | + @base_url_params ||= begin | ||
108 | + url_params = merge_get_params(default_url_params) | ||
109 | + merge_optional_params(url_params) | ||
110 | + end | ||
111 | + | ||
112 | + url_params = @base_url_params.dup | ||
113 | + add_current_page_param(url_params, page) | ||
114 | + | ||
115 | + @template.url_for(url_params) | ||
116 | + end | ||
117 | + | ||
118 | + def merge_get_params(url_params) | ||
119 | + if @template.respond_to? :request and @template.request and @template.request.get? | ||
120 | + symbolized_update(url_params, @template.params) | ||
121 | + end | ||
122 | + url_params | ||
123 | + end | ||
124 | + | ||
125 | + def merge_optional_params(url_params) | ||
126 | + symbolized_update(url_params, @options[:params]) if @options[:params] | ||
127 | + url_params | ||
128 | + end | ||
129 | + | ||
130 | + def add_current_page_param(url_params, page) | ||
131 | + unless param_name.index(/[^\w-]/) | ||
132 | + url_params[param_name.to_sym] = page | ||
133 | + else | ||
134 | + page_param = parse_query_parameters("#{param_name}=#{page}") | ||
135 | + symbolized_update(url_params, page_param) | ||
136 | + end | ||
137 | + end | ||
138 | + | ||
139 | + private | ||
140 | + | ||
141 | + def parse_query_parameters(params) | ||
142 | + Rack::Utils.parse_nested_query(params) | ||
143 | + end | ||
144 | + end | ||
145 | + | ||
146 | + ::ActionView::Base.send :include, self | ||
147 | + end | ||
148 | +end |
vendor/plugins/will_paginate/lib/will_paginate/view_helpers/link_renderer.rb
0 → 100644
@@ -0,0 +1,131 @@ | @@ -0,0 +1,131 @@ | ||
1 | +require 'cgi' | ||
2 | +require 'will_paginate/core_ext' | ||
3 | +require 'will_paginate/view_helpers' | ||
4 | +require 'will_paginate/view_helpers/link_renderer_base' | ||
5 | + | ||
6 | +module WillPaginate | ||
7 | + module ViewHelpers | ||
8 | + # This class does the heavy lifting of actually building the pagination | ||
9 | + # links. It is used by +will_paginate+ helper internally. | ||
10 | + class LinkRenderer < LinkRendererBase | ||
11 | + | ||
12 | + # * +collection+ is a WillPaginate::Collection instance or any other object | ||
13 | + # that conforms to that API | ||
14 | + # * +options+ are forwarded from +will_paginate+ view helper | ||
15 | + # * +template+ is the reference to the template being rendered | ||
16 | + def prepare(collection, options, template) | ||
17 | + super(collection, options) | ||
18 | + @template = template | ||
19 | + @container_attributes = @base_url_params = nil | ||
20 | + end | ||
21 | + | ||
22 | + # Process it! This method returns the complete HTML string which contains | ||
23 | + # pagination links. Feel free to subclass LinkRenderer and change this | ||
24 | + # method as you see fit. | ||
25 | + def to_html | ||
26 | + html = pagination.map do |item| | ||
27 | + item.is_a?(Fixnum) ? | ||
28 | + page_number(item) : | ||
29 | + send(item) | ||
30 | + end.join(@options[:link_separator]) | ||
31 | + | ||
32 | + @options[:container] ? html_container(html) : html | ||
33 | + end | ||
34 | + | ||
35 | + # Returns the subset of +options+ this instance was initialized with that | ||
36 | + # represent HTML attributes for the container element of pagination links. | ||
37 | + def container_attributes | ||
38 | + @container_attributes ||= @options.except(*(ViewHelpers.pagination_options.keys + [:renderer] - [:class])) | ||
39 | + end | ||
40 | + | ||
41 | + protected | ||
42 | + | ||
43 | + def page_number(page) | ||
44 | + unless page == current_page | ||
45 | + link(page, page, :rel => rel_value(page)) | ||
46 | + else | ||
47 | + tag(:em, page, :class => 'current') | ||
48 | + end | ||
49 | + end | ||
50 | + | ||
51 | + def gap | ||
52 | + text = @template.will_paginate_translate(:page_gap) { '…' } | ||
53 | + %(<span class="gap">#{text}</span>) | ||
54 | + end | ||
55 | + | ||
56 | + def previous_page | ||
57 | + num = @collection.current_page > 1 && @collection.current_page - 1 | ||
58 | + previous_or_next_page(num, @options[:previous_label], 'previous_page') | ||
59 | + end | ||
60 | + | ||
61 | + def next_page | ||
62 | + num = @collection.current_page < total_pages && @collection.current_page + 1 | ||
63 | + previous_or_next_page(num, @options[:next_label], 'next_page') | ||
64 | + end | ||
65 | + | ||
66 | + def previous_or_next_page(page, text, classname) | ||
67 | + if page | ||
68 | + link(text, page, :class => classname) | ||
69 | + else | ||
70 | + tag(:span, text, :class => classname + ' disabled') | ||
71 | + end | ||
72 | + end | ||
73 | + | ||
74 | + def html_container(html) | ||
75 | + tag(:div, html, container_attributes) | ||
76 | + end | ||
77 | + | ||
78 | + # Returns URL params for +page_link_or_span+, taking the current GET params | ||
79 | + # and <tt>:params</tt> option into account. | ||
80 | + def url(page) | ||
81 | + raise NotImplementedError | ||
82 | + end | ||
83 | + | ||
84 | + private | ||
85 | + | ||
86 | + def param_name | ||
87 | + @options[:param_name].to_s | ||
88 | + end | ||
89 | + | ||
90 | + def link(text, target, attributes = {}) | ||
91 | + if target.is_a? Fixnum | ||
92 | + attributes[:rel] = rel_value(target) | ||
93 | + target = url(target) | ||
94 | + end | ||
95 | + attributes[:href] = target | ||
96 | + tag(:a, text, attributes) | ||
97 | + end | ||
98 | + | ||
99 | + def tag(name, value, attributes = {}) | ||
100 | + string_attributes = attributes.inject('') do |attrs, pair| | ||
101 | + unless pair.last.nil? | ||
102 | + attrs << %( #{pair.first}="#{CGI::escapeHTML(pair.last.to_s)}") | ||
103 | + end | ||
104 | + attrs | ||
105 | + end | ||
106 | + "<#{name}#{string_attributes}>#{value}</#{name}>" | ||
107 | + end | ||
108 | + | ||
109 | + def rel_value(page) | ||
110 | + case page | ||
111 | + when @collection.current_page - 1; 'prev' + (page == 1 ? ' start' : '') | ||
112 | + when @collection.current_page + 1; 'next' | ||
113 | + when 1; 'start' | ||
114 | + end | ||
115 | + end | ||
116 | + | ||
117 | + def symbolized_update(target, other) | ||
118 | + other.each do |key, value| | ||
119 | + key = key.to_sym | ||
120 | + existing = target[key] | ||
121 | + | ||
122 | + if value.is_a?(Hash) and (existing.is_a?(Hash) or existing.nil?) | ||
123 | + symbolized_update(existing || (target[key] = {}), value) | ||
124 | + else | ||
125 | + target[key] = value | ||
126 | + end | ||
127 | + end | ||
128 | + end | ||
129 | + end | ||
130 | + end | ||
131 | +end |
vendor/plugins/will_paginate/lib/will_paginate/view_helpers/link_renderer_base.rb
0 → 100644
@@ -0,0 +1,77 @@ | @@ -0,0 +1,77 @@ | ||
1 | +module WillPaginate | ||
2 | + module ViewHelpers | ||
3 | + # This class does the heavy lifting of actually building the pagination | ||
4 | + # links. It is used by +will_paginate+ helper internally. | ||
5 | + class LinkRendererBase | ||
6 | + | ||
7 | + # * +collection+ is a WillPaginate::Collection instance or any other object | ||
8 | + # that conforms to that API | ||
9 | + # * +options+ are forwarded from +will_paginate+ view helper | ||
10 | + def prepare(collection, options) | ||
11 | + @collection = collection | ||
12 | + @options = options | ||
13 | + | ||
14 | + # reset values in case we're re-using this instance | ||
15 | + @total_pages = nil | ||
16 | + end | ||
17 | + | ||
18 | + def pagination | ||
19 | + items = @options[:page_links] ? windowed_page_numbers : [] | ||
20 | + items.unshift :previous_page | ||
21 | + items.push :next_page | ||
22 | + end | ||
23 | + | ||
24 | + protected | ||
25 | + | ||
26 | + # Calculates visible page numbers using the <tt>:inner_window</tt> and | ||
27 | + # <tt>:outer_window</tt> options. | ||
28 | + def windowed_page_numbers | ||
29 | + inner_window, outer_window = @options[:inner_window].to_i, @options[:outer_window].to_i | ||
30 | + window_from = current_page - inner_window | ||
31 | + window_to = current_page + inner_window | ||
32 | + | ||
33 | + # adjust lower or upper limit if other is out of bounds | ||
34 | + if window_to > total_pages | ||
35 | + window_from -= window_to - total_pages | ||
36 | + window_to = total_pages | ||
37 | + end | ||
38 | + if window_from < 1 | ||
39 | + window_to += 1 - window_from | ||
40 | + window_from = 1 | ||
41 | + window_to = total_pages if window_to > total_pages | ||
42 | + end | ||
43 | + | ||
44 | + # these are always visible | ||
45 | + middle = window_from..window_to | ||
46 | + | ||
47 | + # left window | ||
48 | + if outer_window + 3 < middle.first # there's a gap | ||
49 | + left = (1..(outer_window + 1)).to_a | ||
50 | + left << :gap | ||
51 | + else # runs into visible pages | ||
52 | + left = 1...middle.first | ||
53 | + end | ||
54 | + | ||
55 | + # right window | ||
56 | + if total_pages - outer_window - 2 > middle.last # again, gap | ||
57 | + right = ((total_pages - outer_window)..total_pages).to_a | ||
58 | + right.unshift :gap | ||
59 | + else # runs into visible pages | ||
60 | + right = (middle.last + 1)..total_pages | ||
61 | + end | ||
62 | + | ||
63 | + left.to_a + middle.to_a + right.to_a | ||
64 | + end | ||
65 | + | ||
66 | + private | ||
67 | + | ||
68 | + def current_page | ||
69 | + @collection.current_page | ||
70 | + end | ||
71 | + | ||
72 | + def total_pages | ||
73 | + @total_pages ||= @collection.total_pages | ||
74 | + end | ||
75 | + end | ||
76 | + end | ||
77 | +end |
vendor/plugins/will_paginate/lib/will_paginate/view_helpers/merb.rb
0 → 100644
@@ -0,0 +1,26 @@ | @@ -0,0 +1,26 @@ | ||
1 | +require 'will_paginate/core_ext' | ||
2 | +require 'will_paginate/view_helpers' | ||
3 | +require 'will_paginate/view_helpers/link_renderer' | ||
4 | + | ||
5 | +module WillPaginate | ||
6 | + module Merb | ||
7 | + include ViewHelpers | ||
8 | + | ||
9 | + def will_paginate(collection, options = {}) #:nodoc: | ||
10 | + options = options.merge(:renderer => LinkRenderer) unless options[:renderer] | ||
11 | + super(collection, options) | ||
12 | + end | ||
13 | + | ||
14 | + class LinkRenderer < ViewHelpers::LinkRenderer | ||
15 | + protected | ||
16 | + | ||
17 | + def url(page) | ||
18 | + params = @template.request.params.except(:action, :controller).merge(param_name => page) | ||
19 | + @template.url(:this, params) | ||
20 | + end | ||
21 | + end | ||
22 | + | ||
23 | + ::Merb::AbstractController.send(:include, self) | ||
24 | + end | ||
25 | +end | ||
26 | + |
vendor/plugins/will_paginate/lib/will_paginate/view_helpers/sinatra.rb
0 → 100644
@@ -0,0 +1,41 @@ | @@ -0,0 +1,41 @@ | ||
1 | +require 'sinatra/base' | ||
2 | +require 'will_paginate/view_helpers' | ||
3 | +require 'will_paginate/view_helpers/link_renderer' | ||
4 | + | ||
5 | +module WillPaginate | ||
6 | + module Sinatra | ||
7 | + module Helpers | ||
8 | + include ViewHelpers | ||
9 | + | ||
10 | + def will_paginate(collection, options = {}) #:nodoc: | ||
11 | + options = options.merge(:renderer => LinkRenderer) unless options[:renderer] | ||
12 | + super(collection, options) | ||
13 | + end | ||
14 | + end | ||
15 | + | ||
16 | + class LinkRenderer < ViewHelpers::LinkRenderer | ||
17 | + protected | ||
18 | + | ||
19 | + def url(page) | ||
20 | + str = File.join(request.script_name.to_s, request.path_info) | ||
21 | + params = request.GET.merge(param_name.to_s => page.to_s) | ||
22 | + params.update @options[:params] if @options[:params] | ||
23 | + str << '?' << build_query(params) | ||
24 | + end | ||
25 | + | ||
26 | + def request | ||
27 | + @template.request | ||
28 | + end | ||
29 | + | ||
30 | + def build_query(params) | ||
31 | + Rack::Utils.build_nested_query params | ||
32 | + end | ||
33 | + end | ||
34 | + | ||
35 | + def self.registered(app) | ||
36 | + app.helpers Helpers | ||
37 | + end | ||
38 | + | ||
39 | + ::Sinatra.register self | ||
40 | + end | ||
41 | +end |
@@ -0,0 +1,12 @@ | @@ -0,0 +1,12 @@ | ||
1 | +#!/usr/bin/env bash | ||
2 | +set -e | ||
3 | + | ||
4 | +if [ -z "$1" ]; then | ||
5 | + echo "Usage: script/each-bundle COMMAND [<ARGS>]" >&2 | ||
6 | + exit 1 | ||
7 | +fi | ||
8 | + | ||
9 | +for gemfile in $(ls Gemfile* | grep -v lock); do | ||
10 | + printf "\e[31m[%s]\e[0m\n" $gemfile | ||
11 | + BUNDLE_GEMFILE=$gemfile "$@" | ||
12 | +done |
@@ -0,0 +1,21 @@ | @@ -0,0 +1,21 @@ | ||
1 | +#!/usr/bin/env bash | ||
2 | +status=0 | ||
3 | + | ||
4 | +run_all(){ | ||
5 | + spec_files="spec" | ||
6 | + [[ $DB != "sqlite3" ]] && spec_files="spec/finders/active_record_spec.rb" | ||
7 | + set -x | ||
8 | + rspec -r fake_rubygems $spec_files | ||
9 | + set +x | ||
10 | +} | ||
11 | + | ||
12 | +export PATH="${PWD}/bin:$PATH" | ||
13 | + | ||
14 | +for db in sqlite3 mysql mysql2 postgres; do | ||
15 | + if ! [[ $db = "mysql2" && $BUNDLE_GEMFILE =~ "rails3.0" ]]; then | ||
16 | + printf "\e[1;33m[DB] ${db}\e[m\n" | ||
17 | + DB=$db run_all || status=1 | ||
18 | + fi | ||
19 | +done | ||
20 | + | ||
21 | +exit $status |
@@ -0,0 +1,139 @@ | @@ -0,0 +1,139 @@ | ||
1 | +require 'will_paginate/array' | ||
2 | +require 'spec_helper' | ||
3 | + | ||
4 | +describe WillPaginate::Collection do | ||
5 | + | ||
6 | + before :all do | ||
7 | + @simple = ('a'..'e').to_a | ||
8 | + end | ||
9 | + | ||
10 | + it "should be a subset of original collection" do | ||
11 | + @simple.paginate(:page => 1, :per_page => 3).should == %w( a b c ) | ||
12 | + end | ||
13 | + | ||
14 | + it "can be shorter than per_page if on last page" do | ||
15 | + @simple.paginate(:page => 2, :per_page => 3).should == %w( d e ) | ||
16 | + end | ||
17 | + | ||
18 | + it "should include whole collection if per_page permits" do | ||
19 | + @simple.paginate(:page => 1, :per_page => 5).should == @simple | ||
20 | + end | ||
21 | + | ||
22 | + it "should be empty if out of bounds" do | ||
23 | + @simple.paginate(:page => 2, :per_page => 5).should be_empty | ||
24 | + end | ||
25 | + | ||
26 | + it "should default to 1 as current page and 30 per-page" do | ||
27 | + result = (1..50).to_a.paginate | ||
28 | + result.current_page.should == 1 | ||
29 | + result.size.should == 30 | ||
30 | + end | ||
31 | + | ||
32 | + it "should give total_entries precedence over actual size" do | ||
33 | + %w(a b c).paginate(:total_entries => 5).total_entries.should == 5 | ||
34 | + end | ||
35 | + | ||
36 | + it "should be an augmented Array" do | ||
37 | + entries = %w(a b c) | ||
38 | + collection = create(2, 3, 10) do |pager| | ||
39 | + pager.replace(entries).should == entries | ||
40 | + end | ||
41 | + | ||
42 | + collection.should == entries | ||
43 | + for method in %w(total_pages each offset size current_page per_page total_entries) | ||
44 | + collection.should respond_to(method) | ||
45 | + end | ||
46 | + collection.should be_kind_of(Array) | ||
47 | + collection.entries.should be_instance_of(Array) | ||
48 | + # TODO: move to another expectation: | ||
49 | + collection.offset.should == 3 | ||
50 | + collection.total_pages.should == 4 | ||
51 | + collection.should_not be_out_of_bounds | ||
52 | + end | ||
53 | + | ||
54 | + describe "previous/next pages" do | ||
55 | + it "should have previous_page nil when on first page" do | ||
56 | + collection = create(1, 1, 3) | ||
57 | + collection.previous_page.should be_nil | ||
58 | + collection.next_page.should == 2 | ||
59 | + end | ||
60 | + | ||
61 | + it "should have both prev/next pages" do | ||
62 | + collection = create(2, 1, 3) | ||
63 | + collection.previous_page.should == 1 | ||
64 | + collection.next_page.should == 3 | ||
65 | + end | ||
66 | + | ||
67 | + it "should have next_page nil when on last page" do | ||
68 | + collection = create(3, 1, 3) | ||
69 | + collection.previous_page.should == 2 | ||
70 | + collection.next_page.should be_nil | ||
71 | + end | ||
72 | + end | ||
73 | + | ||
74 | + describe "out of bounds" do | ||
75 | + it "is out of bounds when page number is too high" do | ||
76 | + create(2, 3, 2).should be_out_of_bounds | ||
77 | + end | ||
78 | + | ||
79 | + it "isn't out of bounds when inside collection" do | ||
80 | + create(1, 3, 2).should_not be_out_of_bounds | ||
81 | + end | ||
82 | + | ||
83 | + it "isn't out of bounds when the collection is empty" do | ||
84 | + collection = create(1, 3, 0) | ||
85 | + collection.should_not be_out_of_bounds | ||
86 | + collection.total_pages.should == 1 | ||
87 | + end | ||
88 | + end | ||
89 | + | ||
90 | + describe "guessing total count" do | ||
91 | + it "can guess when collection is shorter than limit" do | ||
92 | + collection = create { |p| p.replace array } | ||
93 | + collection.total_entries.should == 8 | ||
94 | + end | ||
95 | + | ||
96 | + it "should allow explicit total count to override guessed" do | ||
97 | + collection = create(2, 5, 10) { |p| p.replace array } | ||
98 | + collection.total_entries.should == 10 | ||
99 | + end | ||
100 | + | ||
101 | + it "should not be able to guess when collection is same as limit" do | ||
102 | + collection = create { |p| p.replace array(5) } | ||
103 | + collection.total_entries.should be_nil | ||
104 | + end | ||
105 | + | ||
106 | + it "should not be able to guess when collection is empty" do | ||
107 | + collection = create { |p| p.replace array(0) } | ||
108 | + collection.total_entries.should be_nil | ||
109 | + end | ||
110 | + | ||
111 | + it "should be able to guess when collection is empty and this is the first page" do | ||
112 | + collection = create(1) { |p| p.replace array(0) } | ||
113 | + collection.total_entries.should == 0 | ||
114 | + end | ||
115 | + end | ||
116 | + | ||
117 | + it "should not respond to page_count anymore" do | ||
118 | + Proc.new { create.page_count }.should raise_error(NoMethodError) | ||
119 | + end | ||
120 | + | ||
121 | + it "inherits per_page from global value" do | ||
122 | + collection = described_class.new(1) | ||
123 | + collection.per_page.should == 30 | ||
124 | + end | ||
125 | + | ||
126 | + private | ||
127 | + | ||
128 | + def create(page = 2, limit = 5, total = nil, &block) | ||
129 | + if block_given? | ||
130 | + described_class.create(page, limit, total, &block) | ||
131 | + else | ||
132 | + described_class.new(page, limit, total) | ||
133 | + end | ||
134 | + end | ||
135 | + | ||
136 | + def array(size = 3) | ||
137 | + Array.new(size) | ||
138 | + end | ||
139 | +end |
@@ -0,0 +1,12 @@ | @@ -0,0 +1,12 @@ | ||
1 | +#!/usr/bin/env ruby | ||
2 | +irb = RUBY_PLATFORM =~ /(:?mswin|mingw)/ ? 'irb.bat' : 'irb' | ||
3 | +opts = %w[ --simple-prompt -rirb/completion ] | ||
4 | +if ARGV.include? '-dm' | ||
5 | + opts << '-rwill_paginate/data_mapper' << '-rfinders/data_mapper_test_connector' | ||
6 | +elsif ARGV.include? '-seq' | ||
7 | + opts << '-rwill_paginate/sequel' << '-rfinders/sequel_test_connector' | ||
8 | +else | ||
9 | + opts << '-rconsole_fixtures' | ||
10 | +end | ||
11 | + | ||
12 | +exec 'bundle', 'exec', irb, '-Ilib:spec', *opts |
@@ -0,0 +1,28 @@ | @@ -0,0 +1,28 @@ | ||
1 | +require 'bundler' | ||
2 | +Bundler.setup | ||
3 | + | ||
4 | +require 'will_paginate/active_record' | ||
5 | +require 'finders/activerecord_test_connector' | ||
6 | + | ||
7 | +ActiverecordTestConnector.setup | ||
8 | + | ||
9 | +windows = RUBY_PLATFORM =~ /(:?mswin|mingw)/ | ||
10 | +# used just for the `color` method | ||
11 | +log_subscriber = ActiveSupport::LogSubscriber.log_subscribers.first | ||
12 | + | ||
13 | +IGNORE_SQL = /\b(sqlite_master|sqlite_version)\b|^(CREATE TABLE|PRAGMA)\b/ | ||
14 | + | ||
15 | +ActiveSupport::Notifications.subscribe(/^sql\./) do |*args| | ||
16 | + data = args.last | ||
17 | + unless data[:name] =~ /^Fixture/ or data[:sql] =~ IGNORE_SQL | ||
18 | + if windows | ||
19 | + puts data[:sql] | ||
20 | + else | ||
21 | + puts log_subscriber.send(:color, data[:sql], :cyan) | ||
22 | + end | ||
23 | + end | ||
24 | +end | ||
25 | + | ||
26 | +# load all fixtures | ||
27 | +ActiverecordTestConnector::Fixtures.create_fixtures \ | ||
28 | + ActiverecordTestConnector::FIXTURES_PATH, ActiveRecord::Base.connection.tables |
@@ -0,0 +1,22 @@ | @@ -0,0 +1,22 @@ | ||
1 | +sqlite3: | ||
2 | + database: ":memory:" | ||
3 | + adapter: sqlite3 | ||
4 | + timeout: 500 | ||
5 | + | ||
6 | +mysql: | ||
7 | + adapter: mysql | ||
8 | + database: will_paginate | ||
9 | + username: | ||
10 | + encoding: utf8 | ||
11 | + | ||
12 | +mysql2: | ||
13 | + adapter: mysql2 | ||
14 | + database: will_paginate | ||
15 | + username: | ||
16 | + encoding: utf8 | ||
17 | + | ||
18 | +postgres: | ||
19 | + adapter: postgresql | ||
20 | + database: will_paginate | ||
21 | + username: postgres | ||
22 | + min_messages: warning |
@@ -0,0 +1,18 @@ | @@ -0,0 +1,18 @@ | ||
1 | +# Makes the test suite compatible with Bundler standalone mode (used in CI) | ||
2 | +# because Active Record uses `gem` for loading adapters. | ||
3 | +Kernel.module_eval do | ||
4 | + | ||
5 | + remove_method :gem if 'method' == defined? gem | ||
6 | + | ||
7 | + def gem(*args) | ||
8 | + return if $VERBOSE.nil? | ||
9 | + $stderr << "warning: gem(#{args.map {|o| o.inspect }.join(', ')}) ignored" | ||
10 | + $stderr << "; called from:\n " << caller[0,5].join("\n ") if $DEBUG | ||
11 | + $stderr << "\n" | ||
12 | + end | ||
13 | + | ||
14 | + private :gem | ||
15 | + | ||
16 | +end | ||
17 | + | ||
18 | +$" << "rubygems.rb" |
vendor/plugins/will_paginate/spec/finders/active_record_spec.rb
0 → 100644
@@ -0,0 +1,561 @@ | @@ -0,0 +1,561 @@ | ||
1 | +require 'spec_helper' | ||
2 | +require 'will_paginate/active_record' | ||
3 | +require File.expand_path('../activerecord_test_connector', __FILE__) | ||
4 | + | ||
5 | +ActiverecordTestConnector.setup | ||
6 | +abort unless ActiverecordTestConnector.able_to_connect | ||
7 | + | ||
8 | +describe WillPaginate::ActiveRecord do | ||
9 | + | ||
10 | + extend ActiverecordTestConnector::FixtureSetup | ||
11 | + | ||
12 | + fixtures :topics, :replies, :users, :projects, :developers_projects | ||
13 | + | ||
14 | + it "should integrate with ActiveRecord::Base" do | ||
15 | + ActiveRecord::Base.should respond_to(:paginate) | ||
16 | + end | ||
17 | + | ||
18 | + it "should paginate" do | ||
19 | + lambda { | ||
20 | + users = User.paginate(:page => 1, :per_page => 5).to_a | ||
21 | + users.length.should == 5 | ||
22 | + }.should run_queries(2) | ||
23 | + end | ||
24 | + | ||
25 | + it "should fail when encountering unknown params" do | ||
26 | + lambda { | ||
27 | + User.paginate :foo => 'bar', :page => 1, :per_page => 4 | ||
28 | + }.should raise_error(ArgumentError) | ||
29 | + end | ||
30 | + | ||
31 | + describe "relation" do | ||
32 | + it "should return a relation" do | ||
33 | + rel = nil | ||
34 | + lambda { | ||
35 | + rel = Developer.paginate(:page => 1) | ||
36 | + rel.per_page.should == 10 | ||
37 | + rel.current_page.should == 1 | ||
38 | + }.should run_queries(0) | ||
39 | + | ||
40 | + lambda { | ||
41 | + rel.total_pages.should == 2 | ||
42 | + }.should run_queries(1) | ||
43 | + end | ||
44 | + | ||
45 | + it "should keep per-class per_page number" do | ||
46 | + rel = Developer.order('id').paginate(:page => 1) | ||
47 | + rel.per_page.should == 10 | ||
48 | + end | ||
49 | + | ||
50 | + it "should be able to change per_page number" do | ||
51 | + rel = Developer.order('id').paginate(:page => 1).limit(5) | ||
52 | + rel.per_page.should == 5 | ||
53 | + end | ||
54 | + | ||
55 | + it "remembers pagination in sub-relations" do | ||
56 | + rel = Topic.paginate(:page => 2, :per_page => 3) | ||
57 | + lambda { | ||
58 | + rel.total_entries.should == 4 | ||
59 | + }.should run_queries(1) | ||
60 | + rel = rel.mentions_activerecord | ||
61 | + rel.current_page.should == 2 | ||
62 | + rel.per_page.should == 3 | ||
63 | + lambda { | ||
64 | + rel.total_entries.should == 1 | ||
65 | + }.should run_queries(1) | ||
66 | + end | ||
67 | + | ||
68 | + it "supports the page() method" do | ||
69 | + rel = Developer.page('1').order('id') | ||
70 | + rel.current_page.should == 1 | ||
71 | + rel.per_page.should == 10 | ||
72 | + rel.offset.should == 0 | ||
73 | + | ||
74 | + rel = rel.limit(5).page(2) | ||
75 | + rel.per_page.should == 5 | ||
76 | + rel.offset.should == 5 | ||
77 | + end | ||
78 | + | ||
79 | + it "raises on invalid page number" do | ||
80 | + lambda { | ||
81 | + Developer.page('foo') | ||
82 | + }.should raise_error(ArgumentError) | ||
83 | + end | ||
84 | + | ||
85 | + it "supports first limit() then page()" do | ||
86 | + rel = Developer.limit(3).page(3) | ||
87 | + rel.offset.should == 6 | ||
88 | + end | ||
89 | + | ||
90 | + it "supports first page() then limit()" do | ||
91 | + rel = Developer.page(3).limit(3) | ||
92 | + rel.offset.should == 6 | ||
93 | + end | ||
94 | + | ||
95 | + it "supports #first" do | ||
96 | + rel = Developer.order('id').page(2).per_page(4) | ||
97 | + rel.first.should == users(:dev_5) | ||
98 | + rel.first(2).should == users(:dev_5, :dev_6) | ||
99 | + end | ||
100 | + | ||
101 | + it "supports #last" do | ||
102 | + rel = Developer.order('id').page(2).per_page(4) | ||
103 | + rel.last.should == users(:dev_8) | ||
104 | + rel.last(2).should == users(:dev_7, :dev_8) | ||
105 | + rel.page(3).last.should == users(:poor_jamis) | ||
106 | + end | ||
107 | + | ||
108 | + it "keeps pagination data after 'scoped'" do | ||
109 | + rel = Developer.page(2).scoped | ||
110 | + rel.per_page.should == 10 | ||
111 | + rel.offset.should == 10 | ||
112 | + rel.current_page.should == 2 | ||
113 | + end | ||
114 | + end | ||
115 | + | ||
116 | + describe "counting" do | ||
117 | + it "should guess the total count" do | ||
118 | + lambda { | ||
119 | + topics = Topic.paginate :page => 2, :per_page => 3 | ||
120 | + topics.total_entries.should == 4 | ||
121 | + }.should run_queries(1) | ||
122 | + end | ||
123 | + | ||
124 | + it "should guess that there are no records" do | ||
125 | + lambda { | ||
126 | + topics = Topic.where(:project_id => 999).paginate :page => 1, :per_page => 3 | ||
127 | + topics.total_entries.should == 0 | ||
128 | + }.should run_queries(1) | ||
129 | + end | ||
130 | + | ||
131 | + it "forgets count in sub-relations" do | ||
132 | + lambda { | ||
133 | + topics = Topic.paginate :page => 1, :per_page => 3 | ||
134 | + topics.total_entries.should == 4 | ||
135 | + topics.where('1 = 1').total_entries.should == 4 | ||
136 | + }.should run_queries(2) | ||
137 | + end | ||
138 | + | ||
139 | + it "remembers custom count options in sub-relations" do | ||
140 | + topics = Topic.paginate :page => 1, :per_page => 3, :count => {:conditions => "title LIKE '%futurama%'"} | ||
141 | + topics.total_entries.should == 1 | ||
142 | + topics.length.should == 3 | ||
143 | + lambda { | ||
144 | + topics.order('id').total_entries.should == 1 | ||
145 | + }.should run_queries(1) | ||
146 | + end | ||
147 | + | ||
148 | + it "supports empty? method" do | ||
149 | + topics = Topic.paginate :page => 1, :per_page => 3 | ||
150 | + lambda { | ||
151 | + topics.should_not be_empty | ||
152 | + }.should run_queries(1) | ||
153 | + end | ||
154 | + | ||
155 | + it "support empty? for grouped queries" do | ||
156 | + topics = Topic.group(:project_id).paginate :page => 1, :per_page => 3 | ||
157 | + lambda { | ||
158 | + topics.should_not be_empty | ||
159 | + }.should run_queries(1) | ||
160 | + end | ||
161 | + | ||
162 | + it "supports `size` for grouped queries" do | ||
163 | + topics = Topic.group(:project_id).paginate :page => 1, :per_page => 3 | ||
164 | + lambda { | ||
165 | + topics.size.should == {nil=>2, 1=>2} | ||
166 | + }.should run_queries(1) | ||
167 | + end | ||
168 | + | ||
169 | + it "overrides total_entries count with a fixed value" do | ||
170 | + lambda { | ||
171 | + topics = Topic.paginate :page => 1, :per_page => 3, :total_entries => 999 | ||
172 | + topics.total_entries.should == 999 | ||
173 | + # value is kept even in sub-relations | ||
174 | + topics.where('1 = 1').total_entries.should == 999 | ||
175 | + }.should run_queries(0) | ||
176 | + end | ||
177 | + | ||
178 | + it "supports a non-int for total_entries" do | ||
179 | + topics = Topic.paginate :page => 1, :per_page => 3, :total_entries => "999" | ||
180 | + topics.total_entries.should == 999 | ||
181 | + end | ||
182 | + | ||
183 | + it "removes :include for count" do | ||
184 | + lambda { | ||
185 | + developers = Developer.paginate(:page => 1, :per_page => 1).includes(:projects) | ||
186 | + developers.total_entries.should == 11 | ||
187 | + $query_sql.last.should_not =~ /\bJOIN\b/ | ||
188 | + }.should run_queries(1) | ||
189 | + end | ||
190 | + | ||
191 | + it "keeps :include for count when they are referenced in :conditions" do | ||
192 | + developers = Developer.paginate(:page => 1, :per_page => 1).includes(:projects) | ||
193 | + with_condition = developers.where('projects.id > 1') | ||
194 | + with_condition.total_entries.should == 1 | ||
195 | + | ||
196 | + $query_sql.last.should =~ /\bJOIN\b/ | ||
197 | + end | ||
198 | + | ||
199 | + it "should count with group" do | ||
200 | + Developer.group(:salary).page(1).total_entries.should == 4 | ||
201 | + end | ||
202 | + | ||
203 | + it "removes :reorder for count with group" do | ||
204 | + Project.group(:id).reorder(:id).page(1).total_entries | ||
205 | + $query_sql.last.should_not =~ /\ORDER\b/ | ||
206 | + end | ||
207 | + | ||
208 | + it "should not have zero total_pages when the result set is empty" do | ||
209 | + Developer.where("1 = 2").page(1).total_pages.should == 1 | ||
210 | + end | ||
211 | + end | ||
212 | + | ||
213 | + it "should not ignore :select parameter when it says DISTINCT" do | ||
214 | + users = User.select('DISTINCT salary').paginate :page => 2 | ||
215 | + users.total_entries.should == 5 | ||
216 | + end | ||
217 | + | ||
218 | + describe "paginate_by_sql" do | ||
219 | + it "should respond" do | ||
220 | + User.should respond_to(:paginate_by_sql) | ||
221 | + end | ||
222 | + | ||
223 | + it "should paginate" do | ||
224 | + lambda { | ||
225 | + sql = "select content from topics where content like '%futurama%'" | ||
226 | + topics = Topic.paginate_by_sql sql, :page => 1, :per_page => 1 | ||
227 | + topics.total_entries.should == 1 | ||
228 | + topics.first.attributes.has_key?('title').should be_false | ||
229 | + }.should run_queries(2) | ||
230 | + end | ||
231 | + | ||
232 | + it "should respect total_entries setting" do | ||
233 | + lambda { | ||
234 | + sql = "select content from topics" | ||
235 | + topics = Topic.paginate_by_sql sql, :page => 1, :per_page => 1, :total_entries => 999 | ||
236 | + topics.total_entries.should == 999 | ||
237 | + }.should run_queries(1) | ||
238 | + end | ||
239 | + | ||
240 | + it "defaults to page 1" do | ||
241 | + sql = "select content from topics" | ||
242 | + topics = Topic.paginate_by_sql sql, :page => nil, :per_page => 1 | ||
243 | + topics.current_page.should == 1 | ||
244 | + topics.size.should == 1 | ||
245 | + end | ||
246 | + | ||
247 | + it "should strip the order when counting" do | ||
248 | + lambda { | ||
249 | + sql = "select id, title, content from topics order by topics.title" | ||
250 | + topics = Topic.paginate_by_sql sql, :page => 1, :per_page => 2 | ||
251 | + topics.first.should == topics(:ar) | ||
252 | + }.should run_queries(2) | ||
253 | + | ||
254 | + $query_sql.last.should include('COUNT') | ||
255 | + $query_sql.last.should_not include('order by topics.title') | ||
256 | + end | ||
257 | + | ||
258 | + it "shouldn't change the original query string" do | ||
259 | + query = 'select * from topics where 1 = 2' | ||
260 | + original_query = query.dup | ||
261 | + Topic.paginate_by_sql(query, :page => 1) | ||
262 | + query.should == original_query | ||
263 | + end | ||
264 | + end | ||
265 | + | ||
266 | + it "doesn't mangle options" do | ||
267 | + options = { :page => 1 } | ||
268 | + options.expects(:delete).never | ||
269 | + options_before = options.dup | ||
270 | + | ||
271 | + Topic.paginate(options) | ||
272 | + options.should == options_before | ||
273 | + end | ||
274 | + | ||
275 | + it "should get first page of Topics with a single query" do | ||
276 | + lambda { | ||
277 | + result = Topic.paginate :page => nil | ||
278 | + result.to_a # trigger loading of records | ||
279 | + result.current_page.should == 1 | ||
280 | + result.total_pages.should == 1 | ||
281 | + result.size.should == 4 | ||
282 | + }.should run_queries(1) | ||
283 | + end | ||
284 | + | ||
285 | + it "should get second (inexistent) page of Topics, requiring 2 queries" do | ||
286 | + lambda { | ||
287 | + result = Topic.paginate :page => 2 | ||
288 | + result.total_pages.should == 1 | ||
289 | + result.should be_empty | ||
290 | + }.should run_queries(2) | ||
291 | + end | ||
292 | + | ||
293 | + it "should paginate with :order" do | ||
294 | + result = Topic.paginate :page => 1, :order => 'created_at DESC' | ||
295 | + result.should == topics(:futurama, :harvey_birdman, :rails, :ar).reverse | ||
296 | + result.total_pages.should == 1 | ||
297 | + end | ||
298 | + | ||
299 | + it "should paginate with :conditions" do | ||
300 | + result = Topic.paginate :page => 1, :order => 'id ASC', | ||
301 | + :conditions => ["created_at > ?", 30.minutes.ago] | ||
302 | + result.should == topics(:rails, :ar) | ||
303 | + result.total_pages.should == 1 | ||
304 | + end | ||
305 | + | ||
306 | + it "should paginate with :include and :conditions" do | ||
307 | + result = Topic.paginate \ | ||
308 | + :page => 1, | ||
309 | + :include => :replies, | ||
310 | + :conditions => "replies.content LIKE 'Bird%' ", | ||
311 | + :per_page => 10 | ||
312 | + | ||
313 | + expected = Topic.find :all, | ||
314 | + :include => 'replies', | ||
315 | + :conditions => "replies.content LIKE 'Bird%' ", | ||
316 | + :limit => 10 | ||
317 | + | ||
318 | + result.should == expected | ||
319 | + result.total_entries.should == 1 | ||
320 | + end | ||
321 | + | ||
322 | + it "should paginate with :include and :order" do | ||
323 | + result = nil | ||
324 | + lambda { | ||
325 | + result = Topic.paginate(:page => 1, :include => :replies, :per_page => 10, | ||
326 | + :order => 'replies.created_at asc, topics.created_at asc').to_a | ||
327 | + }.should run_queries(2) | ||
328 | + | ||
329 | + expected = Topic.find :all, | ||
330 | + :include => 'replies', | ||
331 | + :order => 'replies.created_at asc, topics.created_at asc', | ||
332 | + :limit => 10 | ||
333 | + | ||
334 | + result.should == expected | ||
335 | + result.total_entries.should == 4 | ||
336 | + end | ||
337 | + | ||
338 | + describe "associations" do | ||
339 | + it "should paginate with include" do | ||
340 | + project = projects(:active_record) | ||
341 | + | ||
342 | + result = project.topics.paginate \ | ||
343 | + :page => 1, | ||
344 | + :include => :replies, | ||
345 | + :conditions => ["replies.content LIKE ?", 'Nice%'], | ||
346 | + :per_page => 10 | ||
347 | + | ||
348 | + expected = Topic.find :all, | ||
349 | + :include => 'replies', | ||
350 | + :conditions => ["project_id = ? AND replies.content LIKE ?", project.id, 'Nice%'], | ||
351 | + :limit => 10 | ||
352 | + | ||
353 | + result.should == expected | ||
354 | + end | ||
355 | + | ||
356 | + it "should paginate" do | ||
357 | + dhh = users(:david) | ||
358 | + expected_name_ordered = projects(:action_controller, :active_record) | ||
359 | + expected_id_ordered = projects(:active_record, :action_controller) | ||
360 | + | ||
361 | + lambda { | ||
362 | + # with association-specified order | ||
363 | + result = ignore_deprecation { dhh.projects.paginate(:page => 1) } | ||
364 | + result.should == expected_name_ordered | ||
365 | + result.total_entries.should == 2 | ||
366 | + }.should run_queries(2) | ||
367 | + | ||
368 | + # with explicit order | ||
369 | + result = dhh.projects.paginate(:page => 1).reorder('projects.id') | ||
370 | + result.should == expected_id_ordered | ||
371 | + result.total_entries.should == 2 | ||
372 | + | ||
373 | + lambda { | ||
374 | + dhh.projects.find(:all, :order => 'projects.id', :limit => 4) | ||
375 | + }.should_not raise_error | ||
376 | + | ||
377 | + result = dhh.projects.paginate(:page => 1, :per_page => 4).reorder('projects.id') | ||
378 | + result.should == expected_id_ordered | ||
379 | + | ||
380 | + # has_many with implicit order | ||
381 | + topic = Topic.find(1) | ||
382 | + expected = replies(:spam, :witty_retort) | ||
383 | + # FIXME: wow, this is ugly | ||
384 | + topic.replies.paginate(:page => 1).map(&:id).sort.should == expected.map(&:id).sort | ||
385 | + topic.replies.paginate(:page => 1).reorder('replies.id ASC').should == expected.reverse | ||
386 | + end | ||
387 | + | ||
388 | + it "should paginate through association extension" do | ||
389 | + project = Project.order('id').first | ||
390 | + expected = [replies(:brave)] | ||
391 | + | ||
392 | + lambda { | ||
393 | + result = project.replies.only_recent.paginate(:page => 1) | ||
394 | + result.should == expected | ||
395 | + }.should run_queries(1) | ||
396 | + end | ||
397 | + end | ||
398 | + | ||
399 | + it "should paginate with joins" do | ||
400 | + result = nil | ||
401 | + join_sql = 'LEFT JOIN developers_projects ON users.id = developers_projects.developer_id' | ||
402 | + | ||
403 | + lambda { | ||
404 | + result = Developer.paginate(:page => 1, :joins => join_sql, :conditions => 'project_id = 1') | ||
405 | + result.to_a # trigger loading of records | ||
406 | + result.size.should == 2 | ||
407 | + developer_names = result.map(&:name) | ||
408 | + developer_names.should include('David') | ||
409 | + developer_names.should include('Jamis') | ||
410 | + }.should run_queries(1) | ||
411 | + | ||
412 | + lambda { | ||
413 | + expected = result.to_a | ||
414 | + result = Developer.paginate(:page => 1, :joins => join_sql, | ||
415 | + :conditions => 'project_id = 1', :count => { :select => "users.id" }).to_a | ||
416 | + result.should == expected | ||
417 | + result.total_entries.should == 2 | ||
418 | + }.should run_queries(1) | ||
419 | + end | ||
420 | + | ||
421 | + it "should paginate with group" do | ||
422 | + result = nil | ||
423 | + lambda { | ||
424 | + result = Developer.paginate(:page => 1, :per_page => 10, | ||
425 | + :group => 'salary', :select => 'salary', :order => 'salary').to_a | ||
426 | + }.should run_queries(1) | ||
427 | + | ||
428 | + expected = users(:david, :jamis, :dev_10, :poor_jamis).map(&:salary).sort | ||
429 | + result.map(&:salary).should == expected | ||
430 | + end | ||
431 | + | ||
432 | + it "should not paginate with dynamic finder" do | ||
433 | + lambda { | ||
434 | + Developer.paginate_by_salary(100000, :page => 1, :per_page => 5) | ||
435 | + }.should raise_error(NoMethodError) | ||
436 | + end | ||
437 | + | ||
438 | + it "should paginate with_scope" do | ||
439 | + result = Developer.with_poor_ones { Developer.paginate :page => 1 } | ||
440 | + result.size.should == 2 | ||
441 | + result.total_entries.should == 2 | ||
442 | + end | ||
443 | + | ||
444 | + describe "scopes" do | ||
445 | + it "should paginate" do | ||
446 | + result = Developer.poor.paginate :page => 1, :per_page => 1 | ||
447 | + result.size.should == 1 | ||
448 | + result.total_entries.should == 2 | ||
449 | + end | ||
450 | + | ||
451 | + it "should paginate on habtm association" do | ||
452 | + project = projects(:active_record) | ||
453 | + lambda { | ||
454 | + result = ignore_deprecation { project.developers.poor.paginate :page => 1, :per_page => 1 } | ||
455 | + result.size.should == 1 | ||
456 | + result.total_entries.should == 1 | ||
457 | + }.should run_queries(2) | ||
458 | + end | ||
459 | + | ||
460 | + it "should paginate on hmt association" do | ||
461 | + project = projects(:active_record) | ||
462 | + expected = [replies(:brave)] | ||
463 | + | ||
464 | + lambda { | ||
465 | + result = project.replies.recent.paginate :page => 1, :per_page => 1 | ||
466 | + result.should == expected | ||
467 | + result.total_entries.should == 1 | ||
468 | + }.should run_queries(2) | ||
469 | + end | ||
470 | + | ||
471 | + it "should paginate on has_many association" do | ||
472 | + project = projects(:active_record) | ||
473 | + expected = [topics(:ar)] | ||
474 | + | ||
475 | + lambda { | ||
476 | + result = project.topics.mentions_activerecord.paginate :page => 1, :per_page => 1 | ||
477 | + result.should == expected | ||
478 | + result.total_entries.should == 1 | ||
479 | + }.should run_queries(2) | ||
480 | + end | ||
481 | + end | ||
482 | + | ||
483 | + it "should paginate with :readonly option" do | ||
484 | + lambda { | ||
485 | + Developer.paginate :readonly => true, :page => 1 | ||
486 | + }.should_not raise_error | ||
487 | + end | ||
488 | + | ||
489 | + it "should not paginate an array of IDs" do | ||
490 | + lambda { | ||
491 | + Developer.paginate((1..8).to_a, :per_page => 3, :page => 2, :order => 'id') | ||
492 | + }.should raise_error(ArgumentError) | ||
493 | + end | ||
494 | + | ||
495 | + it "errors out for invalid values" do |variable| | ||
496 | + lambda { | ||
497 | + # page that results in an offset larger than BIGINT | ||
498 | + Project.page(307445734561825862) | ||
499 | + }.should raise_error(WillPaginate::InvalidPage, "invalid offset: 9223372036854775830") | ||
500 | + end | ||
501 | + | ||
502 | + protected | ||
503 | + | ||
504 | + def ignore_deprecation | ||
505 | + ActiveSupport::Deprecation.silence { yield } | ||
506 | + end | ||
507 | + | ||
508 | + def run_queries(num) | ||
509 | + QueryCountMatcher.new(num) | ||
510 | + end | ||
511 | + | ||
512 | + def show_queries(&block) | ||
513 | + counter = QueryCountMatcher.new(nil) | ||
514 | + counter.run block | ||
515 | + ensure | ||
516 | + queries = counter.performed_queries | ||
517 | + if queries.any? | ||
518 | + puts queries | ||
519 | + else | ||
520 | + puts "no queries" | ||
521 | + end | ||
522 | + end | ||
523 | + | ||
524 | +end | ||
525 | + | ||
526 | +class QueryCountMatcher | ||
527 | + def initialize(num) | ||
528 | + @expected_count = num | ||
529 | + end | ||
530 | + | ||
531 | + def matches?(block) | ||
532 | + run(block) | ||
533 | + | ||
534 | + if @expected_count.respond_to? :include? | ||
535 | + @expected_count.include? @count | ||
536 | + else | ||
537 | + @count == @expected_count | ||
538 | + end | ||
539 | + end | ||
540 | + | ||
541 | + def run(block) | ||
542 | + $query_count = 0 | ||
543 | + $query_sql = [] | ||
544 | + block.call | ||
545 | + ensure | ||
546 | + @queries = $query_sql.dup | ||
547 | + @count = $query_count | ||
548 | + end | ||
549 | + | ||
550 | + def performed_queries | ||
551 | + @queries | ||
552 | + end | ||
553 | + | ||
554 | + def failure_message | ||
555 | + "expected #{@expected_count} queries, got #{@count}\n#{@queries.join("\n")}" | ||
556 | + end | ||
557 | + | ||
558 | + def negative_failure_message | ||
559 | + "expected query count not to be #{@expected_count}" | ||
560 | + end | ||
561 | +end |
vendor/plugins/will_paginate/spec/finders/activerecord_test_connector.rb
0 → 100644
@@ -0,0 +1,118 @@ | @@ -0,0 +1,118 @@ | ||
1 | +require 'active_record' | ||
2 | +require 'active_record/fixtures' | ||
3 | +require 'active_support/multibyte' # needed for Ruby 1.9.1 | ||
4 | + | ||
5 | +$query_count = 0 | ||
6 | +$query_sql = [] | ||
7 | + | ||
8 | +ignore_sql = / | ||
9 | + ^( | ||
10 | + PRAGMA | SHOW\ max_identifier_length | | ||
11 | + SELECT\ (currval|CAST|@@IDENTITY|@@ROWCOUNT) | | ||
12 | + SHOW\ (FIELDS|TABLES) | ||
13 | + )\b | | ||
14 | + \bFROM\ (sqlite_master|pg_tables|pg_attribute)\b | ||
15 | + /x | ||
16 | + | ||
17 | +ActiveSupport::Notifications.subscribe(/^sql\./) do |*args| | ||
18 | + payload = args.last | ||
19 | + unless payload[:name] =~ /^Fixture/ or payload[:sql] =~ ignore_sql | ||
20 | + $query_count += 1 | ||
21 | + $query_sql << payload[:sql] | ||
22 | + end | ||
23 | +end | ||
24 | + | ||
25 | +module ActiverecordTestConnector | ||
26 | + extend self | ||
27 | + | ||
28 | + attr_accessor :able_to_connect | ||
29 | + attr_accessor :connected | ||
30 | + | ||
31 | + FIXTURES_PATH = File.expand_path('../../fixtures', __FILE__) | ||
32 | + | ||
33 | + Fixtures = defined?(ActiveRecord::FixtureSet) ? ActiveRecord::FixtureSet : | ||
34 | + defined?(ActiveRecord::Fixtures) ? ActiveRecord::Fixtures : | ||
35 | + ::Fixtures | ||
36 | + | ||
37 | + # Set our defaults | ||
38 | + self.connected = false | ||
39 | + self.able_to_connect = true | ||
40 | + | ||
41 | + def setup | ||
42 | + unless self.connected || !self.able_to_connect | ||
43 | + setup_connection | ||
44 | + load_schema | ||
45 | + add_load_path FIXTURES_PATH | ||
46 | + self.connected = true | ||
47 | + end | ||
48 | + rescue Exception => e # errors from ActiveRecord setup | ||
49 | + $stderr.puts "\nSkipping ActiveRecord tests: #{e}\n\n" | ||
50 | + self.able_to_connect = false | ||
51 | + end | ||
52 | + | ||
53 | + private | ||
54 | + | ||
55 | + def add_load_path(path) | ||
56 | + dep = defined?(ActiveSupport::Dependencies) ? ActiveSupport::Dependencies : ::Dependencies | ||
57 | + dep.autoload_paths.unshift path | ||
58 | + end | ||
59 | + | ||
60 | + def setup_connection | ||
61 | + db = ENV['DB'].blank?? 'sqlite3' : ENV['DB'] | ||
62 | + | ||
63 | + configurations = YAML.load_file(File.expand_path('../../database.yml', __FILE__)) | ||
64 | + raise "no configuration for '#{db}'" unless configurations.key? db | ||
65 | + configuration = configurations[db] | ||
66 | + | ||
67 | + # ActiveRecord::Base.logger = Logger.new(STDOUT) if $0 == 'irb' | ||
68 | + puts "using #{configuration['adapter']} adapter" | ||
69 | + | ||
70 | + ActiveRecord::Base.configurations = { db => configuration } | ||
71 | + ActiveRecord::Base.establish_connection(db) | ||
72 | + ActiveRecord::Base.default_timezone = :utc | ||
73 | + end | ||
74 | + | ||
75 | + def load_schema | ||
76 | + silencer = ActiveRecord::Base.method(:silence) | ||
77 | + silence_args = [] | ||
78 | + silence_args << :stdout if silencer.arity != 0 | ||
79 | + silencer.call(*silence_args) do | ||
80 | + ActiveRecord::Migration.verbose = false | ||
81 | + load File.join(FIXTURES_PATH, 'schema.rb') | ||
82 | + end | ||
83 | + end | ||
84 | + | ||
85 | + module FixtureSetup | ||
86 | + def fixtures(*tables) | ||
87 | + table_names = tables.map { |t| t.to_s } | ||
88 | + | ||
89 | + fixtures = Fixtures.create_fixtures ActiverecordTestConnector::FIXTURES_PATH, table_names | ||
90 | + @@loaded_fixtures = {} | ||
91 | + @@fixture_cache = {} | ||
92 | + | ||
93 | + unless fixtures.nil? | ||
94 | + if fixtures.instance_of?(Fixtures) | ||
95 | + @@loaded_fixtures[fixtures.table_name] = fixtures | ||
96 | + else | ||
97 | + fixtures.each { |f| @@loaded_fixtures[f.table_name] = f } | ||
98 | + end | ||
99 | + end | ||
100 | + | ||
101 | + table_names.each do |table_name| | ||
102 | + define_method(table_name) do |*fixtures| | ||
103 | + @@fixture_cache[table_name] ||= {} | ||
104 | + | ||
105 | + instances = fixtures.map do |fixture| | ||
106 | + if @@loaded_fixtures[table_name][fixture.to_s] | ||
107 | + @@fixture_cache[table_name][fixture] ||= @@loaded_fixtures[table_name][fixture.to_s].find | ||
108 | + else | ||
109 | + raise StandardError, "No fixture with name '#{fixture}' found for table '#{table_name}'" | ||
110 | + end | ||
111 | + end | ||
112 | + | ||
113 | + instances.size == 1 ? instances.first : instances | ||
114 | + end | ||
115 | + end | ||
116 | + end | ||
117 | + end | ||
118 | +end |
vendor/plugins/will_paginate/spec/finders/data_mapper_spec.rb
0 → 100644
@@ -0,0 +1,103 @@ | @@ -0,0 +1,103 @@ | ||
1 | +require 'spec_helper' | ||
2 | + | ||
3 | +begin | ||
4 | + require 'will_paginate/data_mapper' | ||
5 | + require File.expand_path('../data_mapper_test_connector', __FILE__) | ||
6 | +rescue LoadError => error | ||
7 | + warn "Error running DataMapper specs: #{error.message}" | ||
8 | + datamapper_loaded = false | ||
9 | +else | ||
10 | + datamapper_loaded = true | ||
11 | +end | ||
12 | + | ||
13 | +describe WillPaginate::DataMapper do | ||
14 | + | ||
15 | + it "has per_page" do | ||
16 | + Animal.per_page.should == 30 | ||
17 | + begin | ||
18 | + Animal.per_page = 10 | ||
19 | + Animal.per_page.should == 10 | ||
20 | + | ||
21 | + subclass = Class.new(Animal) | ||
22 | + subclass.per_page.should == 10 | ||
23 | + ensure | ||
24 | + Animal.per_page = 30 | ||
25 | + end | ||
26 | + end | ||
27 | + | ||
28 | + it "doesn't make normal collections appear paginated" do | ||
29 | + Animal.all.should_not be_paginated | ||
30 | + end | ||
31 | + | ||
32 | + it "paginates to first page by default" do | ||
33 | + animals = Animal.paginate(:page => nil) | ||
34 | + | ||
35 | + animals.should be_paginated | ||
36 | + animals.current_page.should == 1 | ||
37 | + animals.per_page.should == 30 | ||
38 | + animals.offset.should == 0 | ||
39 | + animals.total_entries.should == 3 | ||
40 | + animals.total_pages.should == 1 | ||
41 | + end | ||
42 | + | ||
43 | + it "paginates to first page, explicit limit" do | ||
44 | + animals = Animal.paginate(:page => 1, :per_page => 2) | ||
45 | + | ||
46 | + animals.current_page.should == 1 | ||
47 | + animals.per_page.should == 2 | ||
48 | + animals.total_entries.should == 3 | ||
49 | + animals.total_pages.should == 2 | ||
50 | + animals.map {|a| a.name }.should == %w[ Dog Cat ] | ||
51 | + end | ||
52 | + | ||
53 | + it "paginates to second page" do | ||
54 | + animals = Animal.paginate(:page => 2, :per_page => 2) | ||
55 | + | ||
56 | + animals.current_page.should == 2 | ||
57 | + animals.offset.should == 2 | ||
58 | + animals.map {|a| a.name }.should == %w[ Lion ] | ||
59 | + end | ||
60 | + | ||
61 | + it "paginates a collection" do | ||
62 | + friends = Animal.all(:notes.like => '%friend%') | ||
63 | + friends.paginate(:page => 1).per_page.should == 30 | ||
64 | + friends.paginate(:page => 1, :per_page => 1).total_entries.should == 2 | ||
65 | + end | ||
66 | + | ||
67 | + it "paginates a limited collection" do | ||
68 | + animals = Animal.all(:limit => 2).paginate(:page => 1) | ||
69 | + animals.per_page.should == 2 | ||
70 | + end | ||
71 | + | ||
72 | + it "has page() method" do | ||
73 | + Animal.page(2).per_page.should == 30 | ||
74 | + Animal.page(2).offset.should == 30 | ||
75 | + Animal.page(2).current_page.should == 2 | ||
76 | + Animal.all(:limit => 2).page(2).per_page.should == 2 | ||
77 | + end | ||
78 | + | ||
79 | + it "has total_pages at 1 for empty collections" do | ||
80 | + Animal.all(:conditions => ['1=2']).page(1).total_pages.should == 1 | ||
81 | + end | ||
82 | + | ||
83 | + it "can iterate and then call WP methods" do | ||
84 | + animals = Animal.all(:limit => 2).page(1) | ||
85 | + animals.each { |a| } | ||
86 | + animals.total_entries.should == 3 | ||
87 | + end | ||
88 | + | ||
89 | + it "augments to_a to return a WP::Collection" do | ||
90 | + animals = Animal.all(:limit => 2).page(1) | ||
91 | + array = animals.to_a | ||
92 | + array.size.should == 2 | ||
93 | + array.should be_kind_of(WillPaginate::Collection) | ||
94 | + array.current_page.should == 1 | ||
95 | + array.per_page.should == 2 | ||
96 | + end | ||
97 | + | ||
98 | + it "doesn't have a problem assigning has-one-through relationship" do | ||
99 | + human = Human.create :name => "Mislav" | ||
100 | + human.pet = Animal.first | ||
101 | + end | ||
102 | + | ||
103 | +end if datamapper_loaded |
vendor/plugins/will_paginate/spec/finders/data_mapper_test_connector.rb
0 → 100644
@@ -0,0 +1,54 @@ | @@ -0,0 +1,54 @@ | ||
1 | +require 'sqlite3' | ||
2 | +require 'dm-core' | ||
3 | +require 'dm-core/support/logger' | ||
4 | +require 'dm-migrations' | ||
5 | + | ||
6 | +DataMapper.setup :default, 'sqlite3::memory:' | ||
7 | + | ||
8 | +# Define models | ||
9 | +class Animal | ||
10 | + include DataMapper::Resource | ||
11 | + property :id, Serial | ||
12 | + property :name, String | ||
13 | + property :notes, Text | ||
14 | + | ||
15 | + def self.setup | ||
16 | + Animal.create(:name => 'Dog', :notes => "Man's best friend") | ||
17 | + Animal.create(:name => 'Cat', :notes => "Woman's best friend") | ||
18 | + Animal.create(:name => 'Lion', :notes => 'King of the Jungle') | ||
19 | + end | ||
20 | +end | ||
21 | + | ||
22 | +class Ownership | ||
23 | + include DataMapper::Resource | ||
24 | + | ||
25 | + belongs_to :animal, :key => true | ||
26 | + belongs_to :human, :key => true | ||
27 | + | ||
28 | + def self.setup | ||
29 | + end | ||
30 | +end | ||
31 | + | ||
32 | +class Human | ||
33 | + include DataMapper::Resource | ||
34 | + | ||
35 | + property :id, Serial | ||
36 | + property :name, String | ||
37 | + | ||
38 | + has n, :ownerships | ||
39 | + has 1, :pet, :model => 'Animal', :through => :ownerships, :via => :animal | ||
40 | + | ||
41 | + def self.setup | ||
42 | + end | ||
43 | +end | ||
44 | + | ||
45 | +# Load fixtures | ||
46 | +[Animal, Ownership, Human].each do |klass| | ||
47 | + klass.auto_migrate! | ||
48 | + klass.setup | ||
49 | +end | ||
50 | + | ||
51 | +if 'irb' == $0 | ||
52 | + DataMapper.logger.set_log($stdout, :debug) | ||
53 | + DataMapper.logger.auto_flush = true | ||
54 | +end |
vendor/plugins/will_paginate/spec/finders/mongoid_spec.rb
0 → 100644
@@ -0,0 +1,140 @@ | @@ -0,0 +1,140 @@ | ||
1 | +require 'spec_helper' | ||
2 | + | ||
3 | +begin | ||
4 | + require 'will_paginate/mongoid' | ||
5 | +rescue LoadError => error | ||
6 | + warn "Error running Sequel specs: #{error.message}" | ||
7 | + mongoid_loaded = false | ||
8 | +else | ||
9 | + Mongoid.database = Mongo::Connection.new.db('will_paginate_test') | ||
10 | + | ||
11 | + class MongoidModel | ||
12 | + include Mongoid::Document | ||
13 | + end | ||
14 | + | ||
15 | + mongoid_loaded = true | ||
16 | +end | ||
17 | + | ||
18 | +describe WillPaginate::Mongoid do | ||
19 | + before(:all) do | ||
20 | + MongoidModel.delete_all | ||
21 | + 4.times { MongoidModel.create! } | ||
22 | + end | ||
23 | + | ||
24 | + let(:criteria) { MongoidModel.criteria } | ||
25 | + | ||
26 | + describe "#page" do | ||
27 | + it "should forward to the paginate method" do | ||
28 | + criteria.expects(:paginate).with(:page => 2).returns("itself") | ||
29 | + criteria.page(2).should == "itself" | ||
30 | + end | ||
31 | + | ||
32 | + it "should not override per_page if set earlier in the chain" do | ||
33 | + criteria.paginate(:per_page => 10).page(1).per_page.should == 10 | ||
34 | + criteria.paginate(:per_page => 20).page(1).per_page.should == 20 | ||
35 | + end | ||
36 | + end | ||
37 | + | ||
38 | + describe "#per_page" do | ||
39 | + it "should set the limit if given an argument" do | ||
40 | + criteria.per_page(10).options[:limit].should == 10 | ||
41 | + end | ||
42 | + | ||
43 | + it "should return the current limit if no argument is given" do | ||
44 | + criteria.per_page.should == nil | ||
45 | + criteria.per_page(10).per_page.should == 10 | ||
46 | + end | ||
47 | + | ||
48 | + it "should be interchangable with limit" do | ||
49 | + criteria.limit(15).per_page.should == 15 | ||
50 | + end | ||
51 | + | ||
52 | + it "should be nil'able" do | ||
53 | + criteria.per_page(nil).per_page.should be_nil | ||
54 | + end | ||
55 | + end | ||
56 | + | ||
57 | + describe "#paginate" do | ||
58 | + it "should use criteria" do | ||
59 | + criteria.paginate.should be_instance_of(::Mongoid::Criteria) | ||
60 | + end | ||
61 | + | ||
62 | + it "should not override page number if set earlier in the chain" do | ||
63 | + criteria.page(3).paginate.current_page.should == 3 | ||
64 | + end | ||
65 | + | ||
66 | + it "should limit according to per_page parameter" do | ||
67 | + criteria.paginate(:per_page => 10).options.should include(:limit => 10) | ||
68 | + end | ||
69 | + | ||
70 | + it "should skip according to page and per_page parameters" do | ||
71 | + criteria.paginate(:page => 2, :per_page => 5).options.should include(:skip => 5) | ||
72 | + end | ||
73 | + | ||
74 | + specify "first fallback value for per_page option is the current limit" do | ||
75 | + criteria.limit(12).paginate.options.should include(:limit => 12) | ||
76 | + end | ||
77 | + | ||
78 | + specify "second fallback value for per_page option is WillPaginate.per_page" do | ||
79 | + criteria.paginate.options.should include(:limit => WillPaginate.per_page) | ||
80 | + end | ||
81 | + | ||
82 | + specify "page should default to 1" do | ||
83 | + criteria.paginate.options.should include(:skip => 0) | ||
84 | + end | ||
85 | + | ||
86 | + it "should convert strings to integers" do | ||
87 | + criteria.paginate(:page => "2", :per_page => "3").options.should include(:limit => 3, :limit => 3) | ||
88 | + end | ||
89 | + | ||
90 | + describe "collection compatibility" do | ||
91 | + describe "#total_count" do | ||
92 | + it "should be calculated correctly" do | ||
93 | + criteria.paginate(:per_page => 1).total_entries.should == 4 | ||
94 | + criteria.paginate(:per_page => 3).total_entries.should == 4 | ||
95 | + end | ||
96 | + | ||
97 | + it "should be cached" do | ||
98 | + criteria.expects(:count).once.returns(123) | ||
99 | + criteria.paginate | ||
100 | + 2.times { criteria.total_entries.should == 123 } | ||
101 | + end | ||
102 | + end | ||
103 | + | ||
104 | + it "should calculate total_pages" do | ||
105 | + criteria.paginate(:per_page => 1).total_pages.should == 4 | ||
106 | + criteria.paginate(:per_page => 3).total_pages.should == 2 | ||
107 | + criteria.paginate(:per_page => 10).total_pages.should == 1 | ||
108 | + end | ||
109 | + | ||
110 | + it "should return per_page" do | ||
111 | + criteria.paginate(:per_page => 1).per_page.should == 1 | ||
112 | + criteria.paginate(:per_page => 5).per_page.should == 5 | ||
113 | + end | ||
114 | + | ||
115 | + describe "#current_page" do | ||
116 | + it "should return current_page" do | ||
117 | + criteria.paginate(:page => 1).current_page.should == 1 | ||
118 | + criteria.paginate(:page => 3).current_page.should == 3 | ||
119 | + end | ||
120 | + | ||
121 | + it "should be casted to PageNumber" do | ||
122 | + criteria.paginate(:page => 1).current_page.should be_instance_of(WillPaginate::PageNumber) | ||
123 | + end | ||
124 | + end | ||
125 | + | ||
126 | + it "should return offset" do | ||
127 | + criteria.paginate(:page => 1).offset.should == 0 | ||
128 | + criteria.paginate(:page => 2, :per_page => 5).offset.should == 5 | ||
129 | + criteria.paginate(:page => 3, :per_page => 10).offset.should == 20 | ||
130 | + end | ||
131 | + | ||
132 | + it "should not pollute plain mongoid criterias" do | ||
133 | + %w(total_entries total_pages current_page).each do |method| | ||
134 | + criteria.should_not respond_to(method) | ||
135 | + end | ||
136 | + criteria.offset.should be_nil # this is already a criteria method | ||
137 | + end | ||
138 | + end | ||
139 | + end | ||
140 | +end if mongoid_loaded |
vendor/plugins/will_paginate/spec/finders/sequel_spec.rb
0 → 100644
@@ -0,0 +1,67 @@ | @@ -0,0 +1,67 @@ | ||
1 | +require 'spec_helper' | ||
2 | + | ||
3 | +begin | ||
4 | + require 'will_paginate/sequel' | ||
5 | + require File.expand_path('../sequel_test_connector', __FILE__) | ||
6 | +rescue LoadError, ArgumentError => error | ||
7 | + warn "Error running Sequel specs: #{error.message}" | ||
8 | + sequel_loaded = false | ||
9 | +else | ||
10 | + sequel_loaded = true | ||
11 | +end | ||
12 | + | ||
13 | +describe Sequel::Dataset::Pagination, 'extension' do | ||
14 | + | ||
15 | + class Car < Sequel::Model | ||
16 | + end | ||
17 | + | ||
18 | + it "should have the #paginate method" do | ||
19 | + Car.should respond_to(:paginate) | ||
20 | + end | ||
21 | + | ||
22 | + it "should NOT have the #paginate_by_sql method" do | ||
23 | + Car.should_not respond_to(:paginate_by_sql) | ||
24 | + end | ||
25 | + | ||
26 | + describe 'pagination' do | ||
27 | + before(:all) do | ||
28 | + Car.create(:name => 'Shelby', :notes => "Man's best friend") | ||
29 | + Car.create(:name => 'Aston Martin', :notes => "Woman's best friend") | ||
30 | + Car.create(:name => 'Corvette', :notes => 'King of the Jungle') | ||
31 | + end | ||
32 | + | ||
33 | + it "should imitate WillPaginate::Collection" do | ||
34 | + result = Car.paginate(1, 2) | ||
35 | + | ||
36 | + result.should_not be_empty | ||
37 | + result.size.should == 2 | ||
38 | + result.length.should == 2 | ||
39 | + result.total_entries.should == 3 | ||
40 | + result.total_pages.should == 2 | ||
41 | + result.per_page.should == 2 | ||
42 | + result.current_page.should == 1 | ||
43 | + end | ||
44 | + | ||
45 | + it "should perform" do | ||
46 | + Car.paginate(1, 2).all.should == [Car[1], Car[2]] | ||
47 | + end | ||
48 | + | ||
49 | + it "should be empty" do | ||
50 | + result = Car.paginate(3, 2) | ||
51 | + result.should be_empty | ||
52 | + end | ||
53 | + | ||
54 | + it "should perform with #select and #order" do | ||
55 | + result = Car.select("name as foo".lit).order(:name).paginate(1, 2).all | ||
56 | + result.size.should == 2 | ||
57 | + result.first.values[:foo].should == "Aston Martin" | ||
58 | + end | ||
59 | + | ||
60 | + it "should perform with #filter" do | ||
61 | + results = Car.filter(:name => 'Shelby').paginate(1, 2).all | ||
62 | + results.size.should == 1 | ||
63 | + results.first.should == Car.find(:name => 'Shelby') | ||
64 | + end | ||
65 | + end | ||
66 | + | ||
67 | +end if sequel_loaded |
vendor/plugins/will_paginate/spec/finders/sequel_test_connector.rb
0 → 100644
@@ -0,0 +1,15 @@ | @@ -0,0 +1,15 @@ | ||
1 | +require 'sequel' | ||
2 | + | ||
3 | +Symbol.class_eval do | ||
4 | + # Active Record calculations tries `as` on some objects but chokes when that | ||
5 | + # object was a Symbol and it gets a Sequel::SQL::AliasedExpression. | ||
6 | + undef as if method_defined? :as | ||
7 | +end | ||
8 | + | ||
9 | +db = Sequel.sqlite | ||
10 | + | ||
11 | +db.create_table :cars do | ||
12 | + primary_key :id, :integer, :auto_increment => true | ||
13 | + column :name, :text | ||
14 | + column :notes, :text | ||
15 | +end |
@@ -0,0 +1,15 @@ | @@ -0,0 +1,15 @@ | ||
1 | +class Developer < User | ||
2 | + has_and_belongs_to_many :projects, :include => :topics, :order => 'projects.name', :join_table => 'developers_projects' | ||
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 | + scope :poor, lambda { | ||
11 | + where(['salary <= ?', 80000]).order('salary') | ||
12 | + } | ||
13 | + | ||
14 | + def self.per_page() 10 end | ||
15 | +end |
vendor/plugins/will_paginate/spec/fixtures/developers_projects.yml
0 → 100644
@@ -0,0 +1,13 @@ | @@ -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 | \ No newline at end of file | 14 | \ No newline at end of file |
@@ -0,0 +1,15 @@ | @@ -0,0 +1,15 @@ | ||
1 | +class Project < ActiveRecord::Base | ||
2 | + has_and_belongs_to_many :developers, :uniq => true, :join_table => 'developers_projects' | ||
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 only_recent(params = {}) | ||
10 | + scoped.where(['replies.created_at > ?', 15.minutes.ago]) | ||
11 | + end | ||
12 | + end | ||
13 | + | ||
14 | + has_many :unique_replies, :through => :topics, :source => :replies, :uniq => true | ||
15 | +end |
@@ -0,0 +1,29 @@ | @@ -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.utc.to_s(:db) %> | ||
6 | + | ||
7 | +another: | ||
8 | + id: 2 | ||
9 | + topic_id: 2 | ||
10 | + content: Nuh uh! | ||
11 | + created_at: <%= 1.hour.ago.utc.to_s(:db) %> | ||
12 | + | ||
13 | +spam: | ||
14 | + id: 3 | ||
15 | + topic_id: 1 | ||
16 | + content: Nice site! | ||
17 | + created_at: <%= 1.hour.ago.utc.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.utc.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.utc.to_s(:db) %> |
@@ -0,0 +1,38 @@ | @@ -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,11 @@ | @@ -0,0 +1,11 @@ | ||
1 | +class Topic < ActiveRecord::Base | ||
2 | + has_many :replies, :dependent => :destroy, :order => 'replies.created_at DESC' | ||
3 | + belongs_to :project | ||
4 | + | ||
5 | + scope :mentions_activerecord, lambda { | ||
6 | + where(['topics.title LIKE ?', '%ActiveRecord%']) | ||
7 | + } | ||
8 | + scope :distinct, lambda { | ||
9 | + select("DISTINCT #{table_name}.*") | ||
10 | + } | ||
11 | +end |
@@ -0,0 +1,30 @@ | @@ -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.utc.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.utc.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.utc.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.utc.to_s(:db) %> |
@@ -0,0 +1,35 @@ | @@ -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 |
@@ -0,0 +1,65 @@ | @@ -0,0 +1,65 @@ | ||
1 | +require 'spec_helper' | ||
2 | +require 'will_paginate/page_number' | ||
3 | + | ||
4 | +describe WillPaginate::PageNumber do | ||
5 | + describe "valid" do | ||
6 | + subject { described_class.new('12', 'page') } | ||
7 | + | ||
8 | + it { should eq(12) } | ||
9 | + its(:inspect) { should eq('page 12') } | ||
10 | + it { should be_a(WillPaginate::PageNumber) } | ||
11 | + it { should be_instance_of(WillPaginate::PageNumber) } | ||
12 | + it { should be_a(Numeric) } | ||
13 | + it { should be_a(Fixnum) } | ||
14 | + it { should_not be_instance_of(Fixnum) } | ||
15 | + | ||
16 | + it "passes the PageNumber=== type check" do |variable| | ||
17 | + (WillPaginate::PageNumber === subject).should be | ||
18 | + end | ||
19 | + | ||
20 | + it "passes the Numeric=== type check" do |variable| | ||
21 | + (Numeric === subject).should be | ||
22 | + (Fixnum === subject).should be | ||
23 | + end | ||
24 | + end | ||
25 | + | ||
26 | + describe "invalid" do | ||
27 | + def create(value, name = 'page') | ||
28 | + described_class.new(value, name) | ||
29 | + end | ||
30 | + | ||
31 | + it "errors out on non-int values" do | ||
32 | + lambda { create(nil) }.should raise_error(WillPaginate::InvalidPage) | ||
33 | + lambda { create('') }.should raise_error(WillPaginate::InvalidPage) | ||
34 | + lambda { create('Schnitzel') }.should raise_error(WillPaginate::InvalidPage) | ||
35 | + end | ||
36 | + | ||
37 | + it "errors out on zero or less" do | ||
38 | + lambda { create(0) }.should raise_error(WillPaginate::InvalidPage) | ||
39 | + lambda { create(-1) }.should raise_error(WillPaginate::InvalidPage) | ||
40 | + end | ||
41 | + | ||
42 | + it "doesn't error out on zero for 'offset'" do | ||
43 | + lambda { create(0, 'offset') }.should_not raise_error | ||
44 | + lambda { create(-1, 'offset') }.should raise_error(WillPaginate::InvalidPage) | ||
45 | + end | ||
46 | + end | ||
47 | + | ||
48 | + describe "coercion method" do | ||
49 | + it "defaults to 'page' name" do | ||
50 | + num = WillPaginate::PageNumber(12) | ||
51 | + num.inspect.should eq('page 12') | ||
52 | + end | ||
53 | + | ||
54 | + it "accepts a custom name" do | ||
55 | + num = WillPaginate::PageNumber(12, 'monkeys') | ||
56 | + num.inspect.should eq('monkeys 12') | ||
57 | + end | ||
58 | + | ||
59 | + it "doesn't affect PageNumber instances" do | ||
60 | + num = WillPaginate::PageNumber(12) | ||
61 | + num2 = WillPaginate::PageNumber(num) | ||
62 | + num2.object_id.should eq(num.object_id) | ||
63 | + end | ||
64 | + end | ||
65 | +end |
@@ -0,0 +1,41 @@ | @@ -0,0 +1,41 @@ | ||
1 | +require 'spec_helper' | ||
2 | +require 'will_paginate/per_page' | ||
3 | + | ||
4 | +describe WillPaginate::PerPage do | ||
5 | + | ||
6 | + class MyModel | ||
7 | + extend WillPaginate::PerPage | ||
8 | + end | ||
9 | + | ||
10 | + it "has the default value" do | ||
11 | + MyModel.per_page.should == 30 | ||
12 | + | ||
13 | + WillPaginate.per_page = 10 | ||
14 | + begin | ||
15 | + MyModel.per_page.should == 10 | ||
16 | + ensure | ||
17 | + WillPaginate.per_page = 30 | ||
18 | + end | ||
19 | + end | ||
20 | + | ||
21 | + it "casts values to int" do | ||
22 | + WillPaginate.per_page = '10' | ||
23 | + begin | ||
24 | + MyModel.per_page.should == 10 | ||
25 | + ensure | ||
26 | + WillPaginate.per_page = 30 | ||
27 | + end | ||
28 | + end | ||
29 | + | ||
30 | + it "has an explicit value" do | ||
31 | + MyModel.per_page = 12 | ||
32 | + begin | ||
33 | + MyModel.per_page.should == 12 | ||
34 | + subclass = Class.new(MyModel) | ||
35 | + subclass.per_page.should == 12 | ||
36 | + ensure | ||
37 | + MyModel.send(:remove_instance_variable, '@per_page') | ||
38 | + end | ||
39 | + end | ||
40 | + | ||
41 | +end |
@@ -0,0 +1,71 @@ | @@ -0,0 +1,71 @@ | ||
1 | +require 'rspec' | ||
2 | +require 'view_helpers/view_example_group' | ||
3 | +begin | ||
4 | + require 'ruby-debug' | ||
5 | +rescue LoadError | ||
6 | + # no debugger available | ||
7 | +end | ||
8 | + | ||
9 | +RSpec.configure do |config| | ||
10 | + config.include Module.new { | ||
11 | + protected | ||
12 | + | ||
13 | + def include_phrase(string) | ||
14 | + PhraseMatcher.new(string) | ||
15 | + end | ||
16 | + | ||
17 | + def have_deprecation(msg) | ||
18 | + DeprecationMatcher.new(msg) | ||
19 | + end | ||
20 | + } | ||
21 | + | ||
22 | + config.mock_with :mocha | ||
23 | +end | ||
24 | + | ||
25 | +class PhraseMatcher | ||
26 | + def initialize(string) | ||
27 | + @string = string | ||
28 | + @pattern = /\b#{Regexp.escape string}\b/ | ||
29 | + end | ||
30 | + | ||
31 | + def matches?(actual) | ||
32 | + @actual = actual.to_s | ||
33 | + @actual =~ @pattern | ||
34 | + end | ||
35 | + | ||
36 | + def failure_message | ||
37 | + "expected #{@actual.inspect} to contain phrase #{@string.inspect}" | ||
38 | + end | ||
39 | + | ||
40 | + def negative_failure_message | ||
41 | + "expected #{@actual.inspect} not to contain phrase #{@string.inspect}" | ||
42 | + end | ||
43 | +end | ||
44 | + | ||
45 | +require 'stringio' | ||
46 | + | ||
47 | +class DeprecationMatcher | ||
48 | + def initialize(message) | ||
49 | + @message = message | ||
50 | + end | ||
51 | + | ||
52 | + def matches?(block) | ||
53 | + @actual = hijack_stderr(&block) | ||
54 | + PhraseMatcher.new("DEPRECATION WARNING: #{@message}").matches?(@actual) | ||
55 | + end | ||
56 | + | ||
57 | + def failure_message | ||
58 | + "expected deprecation warning #{@message.inspect}, got #{@actual.inspect}" | ||
59 | + end | ||
60 | + | ||
61 | + private | ||
62 | + | ||
63 | + def hijack_stderr | ||
64 | + err = $stderr | ||
65 | + $stderr = StringIO.new | ||
66 | + yield | ||
67 | + $stderr.string.rstrip | ||
68 | + ensure | ||
69 | + $stderr = err | ||
70 | + end | ||
71 | +end |
vendor/plugins/will_paginate/spec/view_helpers/action_view_spec.rb
0 → 100644
@@ -0,0 +1,423 @@ | @@ -0,0 +1,423 @@ | ||
1 | +require 'spec_helper' | ||
2 | +require 'active_support/rescuable' # needed for Ruby 1.9.1 | ||
3 | +require 'action_controller' | ||
4 | +require 'will_paginate/view_helpers/action_view' | ||
5 | +require 'will_paginate/collection' | ||
6 | + | ||
7 | +Routes = ActionDispatch::Routing::RouteSet.new | ||
8 | + | ||
9 | +Routes.draw do | ||
10 | + get 'dummy/page/:page' => 'dummy#index' | ||
11 | + get 'dummy/dots/page.:page' => 'dummy#dots' | ||
12 | + get 'ibocorp(/:page)' => 'ibocorp#index', | ||
13 | + :constraints => { :page => /\d+/ }, :defaults => { :page => 1 } | ||
14 | + | ||
15 | + get ':controller(/:action(/:id(.:format)))' | ||
16 | +end | ||
17 | + | ||
18 | +describe WillPaginate::ActionView do | ||
19 | + | ||
20 | + before(:all) do | ||
21 | + I18n.load_path.concat WillPaginate::I18n.load_path | ||
22 | + end | ||
23 | + | ||
24 | + before(:each) do | ||
25 | + I18n.reload! | ||
26 | + end | ||
27 | + | ||
28 | + before(:each) do | ||
29 | + @assigns = {} | ||
30 | + @controller = DummyController.new | ||
31 | + @request = @controller.request | ||
32 | + @template = '<%= will_paginate collection, options %>' | ||
33 | + end | ||
34 | + | ||
35 | + attr_reader :assigns, :controller, :request | ||
36 | + | ||
37 | + def render(locals) | ||
38 | + @view = ActionView::Base.new([], @assigns, @controller) | ||
39 | + @view.request = @request | ||
40 | + @view.singleton_class.send(:include, @controller._routes.url_helpers) | ||
41 | + @view.render(:inline => @template, :locals => locals) | ||
42 | + end | ||
43 | + | ||
44 | + ## basic pagination ## | ||
45 | + | ||
46 | + it "should render" do | ||
47 | + paginate do |pagination| | ||
48 | + assert_select 'a[href]', 3 do |elements| | ||
49 | + validate_page_numbers [2,3,2], elements | ||
50 | + assert_select elements.last, ':last-child', "Next →" | ||
51 | + end | ||
52 | + assert_select 'span', 1 | ||
53 | + assert_select 'span.disabled:first-child', '← Previous' | ||
54 | + assert_select 'em.current', '1' | ||
55 | + pagination.first.inner_text.should == '← Previous 1 2 3 Next →' | ||
56 | + end | ||
57 | + end | ||
58 | + | ||
59 | + it "should render nothing when there is only 1 page" do | ||
60 | + paginate(:per_page => 30).should be_empty | ||
61 | + end | ||
62 | + | ||
63 | + it "should paginate with options" do | ||
64 | + paginate({ :page => 2 }, :class => 'will_paginate', :previous_label => 'Prev', :next_label => 'Next') do | ||
65 | + assert_select 'a[href]', 4 do |elements| | ||
66 | + validate_page_numbers [1,1,3,3], elements | ||
67 | + # test rel attribute values: | ||
68 | + assert_select elements[1], 'a', '1' do |link| | ||
69 | + link.first['rel'].should == 'prev start' | ||
70 | + end | ||
71 | + assert_select elements.first, 'a', "Prev" do |link| | ||
72 | + link.first['rel'].should == 'prev start' | ||
73 | + end | ||
74 | + assert_select elements.last, 'a', "Next" do |link| | ||
75 | + link.first['rel'].should == 'next' | ||
76 | + end | ||
77 | + end | ||
78 | + assert_select '.current', '2' | ||
79 | + end | ||
80 | + end | ||
81 | + | ||
82 | + it "should paginate using a custom renderer class" do | ||
83 | + paginate({}, :renderer => AdditionalLinkAttributesRenderer) do | ||
84 | + assert_select 'a[default=true]', 3 | ||
85 | + end | ||
86 | + end | ||
87 | + | ||
88 | + it "should paginate using a custom renderer instance" do | ||
89 | + renderer = WillPaginate::ActionView::LinkRenderer.new | ||
90 | + def renderer.gap() '<span class="my-gap">~~</span>' end | ||
91 | + | ||
92 | + paginate({ :per_page => 2 }, :inner_window => 0, :outer_window => 0, :renderer => renderer) do | ||
93 | + assert_select 'span.my-gap', '~~' | ||
94 | + end | ||
95 | + | ||
96 | + renderer = AdditionalLinkAttributesRenderer.new(:title => 'rendered') | ||
97 | + paginate({}, :renderer => renderer) do | ||
98 | + assert_select 'a[title=rendered]', 3 | ||
99 | + end | ||
100 | + end | ||
101 | + | ||
102 | + it "should have classnames on previous/next links" do | ||
103 | + paginate do |pagination| | ||
104 | + assert_select 'span.disabled.previous_page:first-child' | ||
105 | + assert_select 'a.next_page[href]:last-child' | ||
106 | + end | ||
107 | + end | ||
108 | + | ||
109 | + it "should match expected markup" do | ||
110 | + paginate | ||
111 | + expected = <<-HTML | ||
112 | + <div class="pagination"><span class="previous_page disabled">← Previous</span> | ||
113 | + <em class="current">1</em> | ||
114 | + <a href="/foo/bar?page=2" rel="next">2</a> | ||
115 | + <a href="/foo/bar?page=3">3</a> | ||
116 | + <a href="/foo/bar?page=2" class="next_page" rel="next">Next →</a></div> | ||
117 | + HTML | ||
118 | + expected.strip!.gsub!(/\s{2,}/, ' ') | ||
119 | + expected_dom = HTML::Document.new(expected).root | ||
120 | + | ||
121 | + html_document.root.should == expected_dom | ||
122 | + end | ||
123 | + | ||
124 | + it "should output escaped URLs" do | ||
125 | + paginate({:page => 1, :per_page => 1, :total_entries => 2}, | ||
126 | + :page_links => false, :params => { :tag => '<br>' }) | ||
127 | + | ||
128 | + assert_select 'a[href]', 1 do |links| | ||
129 | + query = links.first['href'].split('?', 2)[1] | ||
130 | + query.split('&').sort.should == %w(page=2 tag=%3Cbr%3E) | ||
131 | + end | ||
132 | + end | ||
133 | + | ||
134 | + ## advanced options for pagination ## | ||
135 | + | ||
136 | + it "should be able to render without container" do | ||
137 | + paginate({}, :container => false) | ||
138 | + assert_select 'div.pagination', 0, 'main DIV present when it shouldn\'t' | ||
139 | + assert_select 'a[href]', 3 | ||
140 | + end | ||
141 | + | ||
142 | + it "should be able to render without page links" do | ||
143 | + paginate({ :page => 2 }, :page_links => false) do | ||
144 | + assert_select 'a[href]', 2 do |elements| | ||
145 | + validate_page_numbers [1,3], elements | ||
146 | + end | ||
147 | + end | ||
148 | + end | ||
149 | + | ||
150 | + ## other helpers ## | ||
151 | + | ||
152 | + it "should render a paginated section" do | ||
153 | + @template = <<-ERB | ||
154 | + <%= paginated_section collection, options do %> | ||
155 | + <%= content_tag :div, '', :id => "developers" %> | ||
156 | + <% end %> | ||
157 | + ERB | ||
158 | + | ||
159 | + paginate | ||
160 | + assert_select 'div.pagination', 2 | ||
161 | + assert_select 'div.pagination + div#developers', 1 | ||
162 | + end | ||
163 | + | ||
164 | + it "should not render a paginated section with a single page" do | ||
165 | + @template = <<-ERB | ||
166 | + <%= paginated_section collection, options do %> | ||
167 | + <%= content_tag :div, '', :id => "developers" %> | ||
168 | + <% end %> | ||
169 | + ERB | ||
170 | + | ||
171 | + paginate(:total_entries => 1) | ||
172 | + assert_select 'div.pagination', 0 | ||
173 | + assert_select 'div#developers', 1 | ||
174 | + end | ||
175 | + | ||
176 | + ## parameter handling in page links ## | ||
177 | + | ||
178 | + it "should preserve parameters on GET" do | ||
179 | + request.params :foo => { :bar => 'baz' } | ||
180 | + paginate | ||
181 | + assert_links_match /foo\[bar\]=baz/ | ||
182 | + end | ||
183 | + | ||
184 | + it "should not preserve parameters on POST" do | ||
185 | + request.post | ||
186 | + request.params :foo => 'bar' | ||
187 | + paginate | ||
188 | + assert_no_links_match /foo=bar/ | ||
189 | + end | ||
190 | + | ||
191 | + it "should add additional parameters to links" do | ||
192 | + paginate({}, :params => { :foo => 'bar' }) | ||
193 | + assert_links_match /foo=bar/ | ||
194 | + end | ||
195 | + | ||
196 | + it "should add anchor parameter" do | ||
197 | + paginate({}, :params => { :anchor => 'anchor' }) | ||
198 | + assert_links_match /#anchor$/ | ||
199 | + end | ||
200 | + | ||
201 | + it "should remove arbitrary parameters" do | ||
202 | + request.params :foo => 'bar' | ||
203 | + paginate({}, :params => { :foo => nil }) | ||
204 | + assert_no_links_match /foo=bar/ | ||
205 | + end | ||
206 | + | ||
207 | + it "should override default route parameters" do | ||
208 | + paginate({}, :params => { :controller => 'baz', :action => 'list' }) | ||
209 | + assert_links_match %r{\Wbaz/list\W} | ||
210 | + end | ||
211 | + | ||
212 | + it "should paginate with custom page parameter" do | ||
213 | + paginate({ :page => 2 }, :param_name => :developers_page) do | ||
214 | + assert_select 'a[href]', 4 do |elements| | ||
215 | + validate_page_numbers [1,1,3,3], elements, :developers_page | ||
216 | + end | ||
217 | + end | ||
218 | + end | ||
219 | + | ||
220 | + it "should paginate with complex custom page parameter" do | ||
221 | + request.params :developers => { :page => 2 } | ||
222 | + | ||
223 | + paginate({ :page => 2 }, :param_name => 'developers[page]') do | ||
224 | + assert_select 'a[href]', 4 do |links| | ||
225 | + assert_links_match /\?developers\[page\]=\d+$/, links | ||
226 | + validate_page_numbers [1,1,3,3], links, 'developers[page]' | ||
227 | + end | ||
228 | + end | ||
229 | + end | ||
230 | + | ||
231 | + it "should paginate with custom route page parameter" do | ||
232 | + request.symbolized_path_parameters.update :controller => 'dummy', :action => nil | ||
233 | + paginate :per_page => 2 do | ||
234 | + assert_select 'a[href]', 6 do |links| | ||
235 | + assert_links_match %r{/page/(\d+)$}, links, [2, 3, 4, 5, 6, 2] | ||
236 | + end | ||
237 | + end | ||
238 | + end | ||
239 | + | ||
240 | + it "should paginate with custom route with dot separator page parameter" do | ||
241 | + request.symbolized_path_parameters.update :controller => 'dummy', :action => 'dots' | ||
242 | + paginate :per_page => 2 do | ||
243 | + assert_select 'a[href]', 6 do |links| | ||
244 | + assert_links_match %r{/page\.(\d+)$}, links, [2, 3, 4, 5, 6, 2] | ||
245 | + end | ||
246 | + end | ||
247 | + end | ||
248 | + | ||
249 | + it "should paginate with custom route and first page number implicit" do | ||
250 | + request.symbolized_path_parameters.update :controller => 'ibocorp', :action => nil | ||
251 | + paginate :page => 2, :per_page => 2 do | ||
252 | + assert_select 'a[href]', 7 do |links| | ||
253 | + assert_links_match %r{/ibocorp(?:/(\d+))?$}, links, [nil, nil, 3, 4, 5, 6, 3] | ||
254 | + end | ||
255 | + end | ||
256 | + # Routes.recognize_path('/ibocorp/2').should == {:page=>'2', :action=>'index', :controller=>'ibocorp'} | ||
257 | + # Routes.recognize_path('/ibocorp/foo').should == {:action=>'foo', :controller=>'ibocorp'} | ||
258 | + end | ||
259 | + | ||
260 | + ## internal hardcore stuff ## | ||
261 | + | ||
262 | + it "should be able to guess the collection name" do | ||
263 | + collection = mock | ||
264 | + collection.expects(:total_pages).returns(1) | ||
265 | + | ||
266 | + @template = '<%= will_paginate options %>' | ||
267 | + controller.controller_name = 'developers' | ||
268 | + assigns['developers'] = collection | ||
269 | + | ||
270 | + paginate(nil) | ||
271 | + end | ||
272 | + | ||
273 | + it "should fail if the inferred collection is nil" do | ||
274 | + @template = '<%= will_paginate options %>' | ||
275 | + controller.controller_name = 'developers' | ||
276 | + | ||
277 | + lambda { | ||
278 | + paginate(nil) | ||
279 | + }.should raise_error(ActionView::TemplateError, /@developers/) | ||
280 | + end | ||
281 | + | ||
282 | + ## i18n | ||
283 | + | ||
284 | + it "is able to translate previous/next labels" do | ||
285 | + translation :will_paginate => { | ||
286 | + :previous_label => 'Go back', | ||
287 | + :next_label => 'Load more' | ||
288 | + } | ||
289 | + | ||
290 | + paginate do |pagination| | ||
291 | + assert_select 'span.disabled:first-child', 'Go back' | ||
292 | + assert_select 'a[rel=next]', 'Load more' | ||
293 | + end | ||
294 | + end | ||
295 | + | ||
296 | + it "renders using ActionView helpers on a custom object" do | ||
297 | + helper = Object.new | ||
298 | + class << helper | ||
299 | + attr_reader :controller | ||
300 | + include ActionView::Helpers::UrlHelper | ||
301 | + include Routes.url_helpers | ||
302 | + include WillPaginate::ActionView | ||
303 | + end | ||
304 | + helper.default_url_options[:controller] = 'dummy' | ||
305 | + | ||
306 | + collection = WillPaginate::Collection.new(2, 1, 3) | ||
307 | + @render_output = helper.will_paginate(collection) | ||
308 | + | ||
309 | + assert_select 'a[href]', 4 do |links| | ||
310 | + urls = links.map {|l| l['href'] }.uniq | ||
311 | + urls.should == ['/dummy/page/1', '/dummy/page/3'] | ||
312 | + end | ||
313 | + end | ||
314 | + | ||
315 | + it "renders using ActionDispatch helper on a custom object" do | ||
316 | + helper = Object.new | ||
317 | + class << helper | ||
318 | + include ActionDispatch::Routing::UrlFor | ||
319 | + include Routes.url_helpers | ||
320 | + include WillPaginate::ActionView | ||
321 | + end | ||
322 | + helper.default_url_options[:host] = 'example.com' | ||
323 | + helper.default_url_options[:controller] = 'dummy' | ||
324 | + # helper.default_url_options[:only_path] = true | ||
325 | + | ||
326 | + collection = WillPaginate::Collection.new(2, 1, 3) | ||
327 | + @render_output = helper.will_paginate(collection) | ||
328 | + | ||
329 | + assert_select 'a[href]', 4 do |links| | ||
330 | + urls = links.map {|l| l['href'] }.uniq | ||
331 | + urls.should == ['http://example.com/dummy/page/1', 'http://example.com/dummy/page/3'] | ||
332 | + end | ||
333 | + end | ||
334 | + | ||
335 | + private | ||
336 | + | ||
337 | + def translation(data) | ||
338 | + I18n.available_locales # triggers loading existing translations | ||
339 | + I18n.backend.store_translations(:en, data) | ||
340 | + end | ||
341 | +end | ||
342 | + | ||
343 | +class AdditionalLinkAttributesRenderer < WillPaginate::ActionView::LinkRenderer | ||
344 | + def initialize(link_attributes = nil) | ||
345 | + super() | ||
346 | + @additional_link_attributes = link_attributes || { :default => 'true' } | ||
347 | + end | ||
348 | + | ||
349 | + def link(text, target, attributes = {}) | ||
350 | + super(text, target, attributes.merge(@additional_link_attributes)) | ||
351 | + end | ||
352 | +end | ||
353 | + | ||
354 | +class DummyController | ||
355 | + attr_reader :request | ||
356 | + attr_accessor :controller_name | ||
357 | + | ||
358 | + include ActionController::UrlFor | ||
359 | + include Routes.url_helpers | ||
360 | + | ||
361 | + def initialize | ||
362 | + @request = DummyRequest.new | ||
363 | + end | ||
364 | + | ||
365 | + def params | ||
366 | + @request.params | ||
367 | + end | ||
368 | + | ||
369 | + def env | ||
370 | + {} | ||
371 | + end | ||
372 | + | ||
373 | + def _prefixes | ||
374 | + [] | ||
375 | + end | ||
376 | +end | ||
377 | + | ||
378 | +class IbocorpController < DummyController | ||
379 | +end | ||
380 | + | ||
381 | +class DummyRequest | ||
382 | + attr_accessor :symbolized_path_parameters | ||
383 | + | ||
384 | + def initialize | ||
385 | + @get = true | ||
386 | + @params = {} | ||
387 | + @symbolized_path_parameters = { :controller => 'foo', :action => 'bar' } | ||
388 | + end | ||
389 | + | ||
390 | + def get? | ||
391 | + @get | ||
392 | + end | ||
393 | + | ||
394 | + def post | ||
395 | + @get = false | ||
396 | + end | ||
397 | + | ||
398 | + def relative_url_root | ||
399 | + '' | ||
400 | + end | ||
401 | + | ||
402 | + def script_name | ||
403 | + '' | ||
404 | + end | ||
405 | + | ||
406 | + def params(more = nil) | ||
407 | + @params.update(more) if more | ||
408 | + @params | ||
409 | + end | ||
410 | + | ||
411 | + def host_with_port | ||
412 | + 'example.com' | ||
413 | + end | ||
414 | + alias host host_with_port | ||
415 | + | ||
416 | + def optional_port | ||
417 | + '' | ||
418 | + end | ||
419 | + | ||
420 | + def protocol | ||
421 | + 'http:' | ||
422 | + end | ||
423 | +end |
vendor/plugins/will_paginate/spec/view_helpers/base_spec.rb
0 → 100644
@@ -0,0 +1,142 @@ | @@ -0,0 +1,142 @@ | ||
1 | +require 'spec_helper' | ||
2 | +require 'will_paginate/view_helpers' | ||
3 | +require 'will_paginate/array' | ||
4 | +require 'active_support' | ||
5 | +require 'active_support/core_ext/string/inflections' | ||
6 | +require 'active_support/inflections' | ||
7 | + | ||
8 | +describe WillPaginate::ViewHelpers do | ||
9 | + | ||
10 | + before(:all) do | ||
11 | + # make sure default translations aren't loaded | ||
12 | + I18n.load_path.clear | ||
13 | + end | ||
14 | + | ||
15 | + before(:each) do | ||
16 | + I18n.reload! | ||
17 | + end | ||
18 | + | ||
19 | + include WillPaginate::ViewHelpers | ||
20 | + | ||
21 | + describe "will_paginate" do | ||
22 | + it "should render" do | ||
23 | + collection = WillPaginate::Collection.new(1, 2, 4) | ||
24 | + renderer = mock 'Renderer' | ||
25 | + renderer.expects(:prepare).with(collection, instance_of(Hash), self) | ||
26 | + renderer.expects(:to_html).returns('<PAGES>') | ||
27 | + | ||
28 | + will_paginate(collection, :renderer => renderer).should == '<PAGES>' | ||
29 | + end | ||
30 | + | ||
31 | + it "should return nil for single-page collections" do | ||
32 | + collection = mock 'Collection', :total_pages => 1 | ||
33 | + will_paginate(collection).should be_nil | ||
34 | + end | ||
35 | + | ||
36 | + it "should call html_safe on result" do | ||
37 | + collection = WillPaginate::Collection.new(1, 2, 4) | ||
38 | + | ||
39 | + html = mock 'HTML' | ||
40 | + html.expects(:html_safe).returns(html) | ||
41 | + renderer = mock 'Renderer' | ||
42 | + renderer.stubs(:prepare) | ||
43 | + renderer.expects(:to_html).returns(html) | ||
44 | + | ||
45 | + will_paginate(collection, :renderer => renderer).should eql(html) | ||
46 | + end | ||
47 | + end | ||
48 | + | ||
49 | + describe "pagination_options" do | ||
50 | + let(:pagination_options) { WillPaginate::ViewHelpers.pagination_options } | ||
51 | + | ||
52 | + it "deprecates setting :renderer" do | ||
53 | + begin | ||
54 | + lambda { | ||
55 | + pagination_options[:renderer] = 'test' | ||
56 | + }.should have_deprecation("pagination_options[:renderer] shouldn't be set") | ||
57 | + ensure | ||
58 | + pagination_options.delete :renderer | ||
59 | + end | ||
60 | + end | ||
61 | + end | ||
62 | + | ||
63 | + describe "page_entries_info" do | ||
64 | + before :all do | ||
65 | + @array = ('a'..'z').to_a | ||
66 | + end | ||
67 | + | ||
68 | + def info(params, options = {}) | ||
69 | + collection = Hash === params ? @array.paginate(params) : params | ||
70 | + page_entries_info collection, {:html => false}.merge(options) | ||
71 | + end | ||
72 | + | ||
73 | + it "should display middle results and total count" do | ||
74 | + info(:page => 2, :per_page => 5).should == "Displaying strings 6 - 10 of 26 in total" | ||
75 | + end | ||
76 | + | ||
77 | + it "uses translation if available" do | ||
78 | + translation :will_paginate => { | ||
79 | + :page_entries_info => {:multi_page => 'Showing %{from} - %{to}'} | ||
80 | + } | ||
81 | + info(:page => 2, :per_page => 5).should == "Showing 6 - 10" | ||
82 | + end | ||
83 | + | ||
84 | + it "uses specific translation if available" do | ||
85 | + translation :will_paginate => { | ||
86 | + :page_entries_info => {:multi_page => 'Showing %{from} - %{to}'}, | ||
87 | + :string => { :page_entries_info => {:multi_page => 'Strings %{from} to %{to}'} } | ||
88 | + } | ||
89 | + info(:page => 2, :per_page => 5).should == "Strings 6 to 10" | ||
90 | + end | ||
91 | + | ||
92 | + it "should output HTML by default" do | ||
93 | + info({ :page => 2, :per_page => 5 }, :html => true).should == | ||
94 | + "Displaying strings <b>6 - 10</b> of <b>26</b> in total" | ||
95 | + end | ||
96 | + | ||
97 | + it "should display shortened end results" do | ||
98 | + info(:page => 7, :per_page => 4).should include_phrase('strings 25 - 26') | ||
99 | + end | ||
100 | + | ||
101 | + it "should handle longer class names" do | ||
102 | + collection = @array.paginate(:page => 2, :per_page => 5) | ||
103 | + model = stub('Class', :name => 'ProjectType', :to_s => 'ProjectType') | ||
104 | + collection.first.stubs(:class).returns(model) | ||
105 | + info(collection).should include_phrase('project types') | ||
106 | + end | ||
107 | + | ||
108 | + it "should adjust output for single-page collections" do | ||
109 | + info(('a'..'d').to_a.paginate(:page => 1, :per_page => 5)).should == "Displaying all 4 strings" | ||
110 | + info(['a'].paginate(:page => 1, :per_page => 5)).should == "Displaying 1 string" | ||
111 | + end | ||
112 | + | ||
113 | + it "should display 'no entries found' for empty collections" do | ||
114 | + info([].paginate(:page => 1, :per_page => 5)).should == "No entries found" | ||
115 | + end | ||
116 | + | ||
117 | + it "uses model_name.human when available" do | ||
118 | + name = stub('model name', :i18n_key => :flower_key) | ||
119 | + name.expects(:human).with(:count => 1).returns('flower') | ||
120 | + model = stub('Class', :model_name => name) | ||
121 | + collection = [1].paginate(:page => 1) | ||
122 | + | ||
123 | + info(collection, :model => model).should == "Displaying 1 flower" | ||
124 | + end | ||
125 | + | ||
126 | + it "uses custom translation instead of model_name.human" do | ||
127 | + name = stub('model name', :i18n_key => :flower_key) | ||
128 | + name.expects(:human).never | ||
129 | + model = stub('Class', :model_name => name) | ||
130 | + translation :will_paginate => {:models => {:flower_key => 'tulip'}} | ||
131 | + collection = [1].paginate(:page => 1) | ||
132 | + | ||
133 | + info(collection, :model => model).should == "Displaying 1 tulip" | ||
134 | + end | ||
135 | + | ||
136 | + private | ||
137 | + | ||
138 | + def translation(data) | ||
139 | + I18n.backend.store_translations(:en, data) | ||
140 | + end | ||
141 | + end | ||
142 | +end |
vendor/plugins/will_paginate/spec/view_helpers/link_renderer_base_spec.rb
0 → 100644
@@ -0,0 +1,87 @@ | @@ -0,0 +1,87 @@ | ||
1 | +require 'spec_helper' | ||
2 | +require 'will_paginate/view_helpers/link_renderer_base' | ||
3 | +require 'will_paginate/collection' | ||
4 | + | ||
5 | +describe WillPaginate::ViewHelpers::LinkRendererBase do | ||
6 | + | ||
7 | + before do | ||
8 | + @renderer = described_class.new | ||
9 | + end | ||
10 | + | ||
11 | + it "should raise error when unprepared" do | ||
12 | + lambda { | ||
13 | + @renderer.pagination | ||
14 | + }.should raise_error | ||
15 | + end | ||
16 | + | ||
17 | + it "should prepare with collection and options" do | ||
18 | + prepare({}) | ||
19 | + @renderer.send(:current_page).should == 1 | ||
20 | + end | ||
21 | + | ||
22 | + it "should have total_pages accessor" do | ||
23 | + prepare :total_pages => 42 | ||
24 | + @renderer.send(:total_pages).should == 42 | ||
25 | + end | ||
26 | + | ||
27 | + it "should clear old cached values when prepared" do | ||
28 | + prepare(:total_pages => 1) | ||
29 | + @renderer.send(:total_pages).should == 1 | ||
30 | + # prepare with different object: | ||
31 | + prepare(:total_pages => 2) | ||
32 | + @renderer.send(:total_pages).should == 2 | ||
33 | + end | ||
34 | + | ||
35 | + it "should have pagination definition" do | ||
36 | + prepare({ :total_pages => 1 }, :page_links => true) | ||
37 | + @renderer.pagination.should == [:previous_page, 1, :next_page] | ||
38 | + end | ||
39 | + | ||
40 | + describe "visible page numbers" do | ||
41 | + it "should calculate windowed visible links" do | ||
42 | + prepare({ :page => 6, :total_pages => 11 }, :inner_window => 1, :outer_window => 1) | ||
43 | + showing_pages 1, 2, :gap, 5, 6, 7, :gap, 10, 11 | ||
44 | + end | ||
45 | + | ||
46 | + it "should eliminate small gaps" do | ||
47 | + prepare({ :page => 6, :total_pages => 11 }, :inner_window => 2, :outer_window => 1) | ||
48 | + # pages 4 and 8 appear instead of the gap | ||
49 | + showing_pages 1..11 | ||
50 | + end | ||
51 | + | ||
52 | + it "should support having no windows at all" do | ||
53 | + prepare({ :page => 4, :total_pages => 7 }, :inner_window => 0, :outer_window => 0) | ||
54 | + showing_pages 1, :gap, 4, :gap, 7 | ||
55 | + end | ||
56 | + | ||
57 | + it "should adjust upper limit if lower is out of bounds" do | ||
58 | + prepare({ :page => 1, :total_pages => 10 }, :inner_window => 2, :outer_window => 1) | ||
59 | + showing_pages 1, 2, 3, 4, 5, :gap, 9, 10 | ||
60 | + end | ||
61 | + | ||
62 | + it "should adjust lower limit if upper is out of bounds" do | ||
63 | + prepare({ :page => 10, :total_pages => 10 }, :inner_window => 2, :outer_window => 1) | ||
64 | + showing_pages 1, 2, :gap, 6, 7, 8, 9, 10 | ||
65 | + end | ||
66 | + | ||
67 | + def showing_pages(*pages) | ||
68 | + pages = pages.first.to_a if Array === pages.first or Range === pages.first | ||
69 | + @renderer.send(:windowed_page_numbers).should == pages | ||
70 | + end | ||
71 | + end | ||
72 | + | ||
73 | + protected | ||
74 | + | ||
75 | + def collection(params = {}) | ||
76 | + if params[:total_pages] | ||
77 | + params[:per_page] = 1 | ||
78 | + params[:total_entries] = params[:total_pages] | ||
79 | + end | ||
80 | + WillPaginate::Collection.new(params[:page] || 1, params[:per_page] || 30, params[:total_entries]) | ||
81 | + end | ||
82 | + | ||
83 | + def prepare(collection_options, options = {}) | ||
84 | + @renderer.prepare(collection(collection_options), options) | ||
85 | + end | ||
86 | + | ||
87 | +end |
vendor/plugins/will_paginate/spec/view_helpers/view_example_group.rb
0 → 100644
@@ -0,0 +1,121 @@ | @@ -0,0 +1,121 @@ | ||
1 | +require 'active_support' | ||
2 | +begin | ||
3 | + require 'minitest/unit' | ||
4 | +rescue LoadError | ||
5 | + # Fails on Ruby 1.8, but it's OK since we only need MiniTest::Assertions | ||
6 | + # on Rails 4 which doesn't support 1.8 anyway. | ||
7 | +end | ||
8 | +require 'action_dispatch/testing/assertions' | ||
9 | +require 'will_paginate/array' | ||
10 | + | ||
11 | +module ViewExampleGroup | ||
12 | + | ||
13 | + include ActionDispatch::Assertions::SelectorAssertions | ||
14 | + include MiniTest::Assertions if defined? MiniTest | ||
15 | + | ||
16 | + def assert(value, message) | ||
17 | + raise message unless value | ||
18 | + end | ||
19 | + | ||
20 | + def paginate(collection = {}, options = {}, &block) | ||
21 | + if collection.instance_of? Hash | ||
22 | + page_options = { :page => 1, :total_entries => 11, :per_page => 4 }.merge(collection) | ||
23 | + collection = [1].paginate(page_options) | ||
24 | + end | ||
25 | + | ||
26 | + locals = { :collection => collection, :options => options } | ||
27 | + | ||
28 | + @render_output = render(locals) | ||
29 | + @html_document = nil | ||
30 | + | ||
31 | + if block_given? | ||
32 | + classname = options[:class] || WillPaginate::ViewHelpers.pagination_options[:class] | ||
33 | + assert_select("div.#{classname}", 1, 'no main DIV', &block) | ||
34 | + end | ||
35 | + | ||
36 | + @render_output | ||
37 | + end | ||
38 | + | ||
39 | + def html_document | ||
40 | + @html_document ||= HTML::Document.new(@render_output, true, false) | ||
41 | + end | ||
42 | + | ||
43 | + def response_from_page_or_rjs | ||
44 | + html_document.root | ||
45 | + end | ||
46 | + | ||
47 | + def validate_page_numbers(expected, links, param_name = :page) | ||
48 | + param_pattern = /\W#{Regexp.escape(param_name.to_s)}=([^&]*)/ | ||
49 | + | ||
50 | + links.map { |el| | ||
51 | + unescape_href(el) =~ param_pattern | ||
52 | + $1 ? $1.to_i : $1 | ||
53 | + }.should == expected | ||
54 | + end | ||
55 | + | ||
56 | + def assert_links_match(pattern, links = nil, numbers = nil) | ||
57 | + links ||= assert_select 'div.pagination a[href]' do |elements| | ||
58 | + elements | ||
59 | + end | ||
60 | + | ||
61 | + pages = [] if numbers | ||
62 | + | ||
63 | + links.each do |el| | ||
64 | + href = unescape_href(el) | ||
65 | + href.should =~ pattern | ||
66 | + if numbers | ||
67 | + href =~ pattern | ||
68 | + pages << ($1.nil?? nil : $1.to_i) | ||
69 | + end | ||
70 | + end | ||
71 | + | ||
72 | + pages.should == numbers if numbers | ||
73 | + end | ||
74 | + | ||
75 | + def assert_no_links_match(pattern) | ||
76 | + assert_select 'div.pagination a[href]' do |elements| | ||
77 | + elements.each do |el| | ||
78 | + unescape_href(el).should_not =~ pattern | ||
79 | + end | ||
80 | + end | ||
81 | + end | ||
82 | + | ||
83 | + def unescape_href(el) | ||
84 | + CGI.unescape CGI.unescapeHTML(el['href']) | ||
85 | + end | ||
86 | + | ||
87 | + def build_message(message, pattern, *args) | ||
88 | + built_message = pattern.dup | ||
89 | + for value in args | ||
90 | + built_message.sub! '?', value.inspect | ||
91 | + end | ||
92 | + built_message | ||
93 | + end | ||
94 | + | ||
95 | +end | ||
96 | + | ||
97 | +RSpec.configure do |config| | ||
98 | + config.include ViewExampleGroup, :type => :view, :example_group => { | ||
99 | + :file_path => %r{spec/view_helpers/} | ||
100 | + } | ||
101 | +end | ||
102 | + | ||
103 | +module HTML | ||
104 | + Node.class_eval do | ||
105 | + def inner_text | ||
106 | + children.map(&:inner_text).join('') | ||
107 | + end | ||
108 | + end | ||
109 | + | ||
110 | + Text.class_eval do | ||
111 | + def inner_text | ||
112 | + self.to_s | ||
113 | + end | ||
114 | + end | ||
115 | + | ||
116 | + Tag.class_eval do | ||
117 | + def inner_text | ||
118 | + childless?? '' : super | ||
119 | + end | ||
120 | + end | ||
121 | +end |
@@ -0,0 +1,30 @@ | @@ -0,0 +1,30 @@ | ||
1 | +# encoding: utf-8 | ||
2 | +require 'rbconfig' | ||
3 | +require File.expand_path('../lib/will_paginate/version', __FILE__) | ||
4 | + | ||
5 | +Gem::Specification.new do |s| | ||
6 | + s.name = 'will_paginate' | ||
7 | + s.version = WillPaginate::VERSION::STRING | ||
8 | + | ||
9 | + s.summary = "Pagination plugin for web frameworks and other apps" | ||
10 | + s.description = "will_paginate provides a simple API for performing paginated queries with Active Record, DataMapper and Sequel, and includes helpers for rendering pagination links in Rails, Sinatra and Merb web apps." | ||
11 | + | ||
12 | + s.authors = ['Mislav Marohnić'] | ||
13 | + s.email = 'mislav.marohnic@gmail.com' | ||
14 | + s.homepage = 'https://github.com/mislav/will_paginate/wiki' | ||
15 | + s.license = 'MIT' | ||
16 | + | ||
17 | + s.rdoc_options = ['--main', 'README.md', '--charset=UTF-8'] | ||
18 | + s.extra_rdoc_files = ['README.md', 'LICENSE'] | ||
19 | + | ||
20 | + s.files = Dir['Rakefile', '{bin,lib,test,spec}/**/*', 'README*', 'LICENSE*'] | ||
21 | + | ||
22 | + # include only files in version control | ||
23 | + git_dir = File.expand_path('../.git', __FILE__) | ||
24 | + void = defined?(File::NULL) ? File::NULL : | ||
25 | + RbConfig::CONFIG['host_os'] =~ /msdos|mswin|djgpp|mingw/ ? 'NUL' : '/dev/null' | ||
26 | + | ||
27 | + if File.directory?(git_dir) and system "git --version >>#{void} 2>&1" | ||
28 | + s.files &= `git --git-dir='#{git_dir}' ls-files -z`.split("\0") | ||
29 | + end | ||
30 | +end |