summaryrefslogtreecommitdiff
path: root/vendor/plugins
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/plugins')
-rw-r--r--vendor/plugins/will_paginate/.gitignore4
-rw-r--r--vendor/plugins/will_paginate/.manifest49
-rw-r--r--vendor/plugins/will_paginate/CHANGELOG.rdoc110
-rw-r--r--vendor/plugins/will_paginate/LICENSE18
-rw-r--r--vendor/plugins/will_paginate/README.rdoc107
-rw-r--r--vendor/plugins/will_paginate/Rakefile62
-rw-r--r--vendor/plugins/will_paginate/examples/apple-circle.gifbin0 -> 178 bytes
-rw-r--r--vendor/plugins/will_paginate/examples/index.haml69
-rw-r--r--vendor/plugins/will_paginate/examples/index.html92
-rw-r--r--vendor/plugins/will_paginate/examples/pagination.css90
-rw-r--r--vendor/plugins/will_paginate/examples/pagination.sass91
-rw-r--r--vendor/plugins/will_paginate/init.rb1
-rw-r--r--vendor/plugins/will_paginate/lib/will_paginate.rb78
-rw-r--r--vendor/plugins/will_paginate/lib/will_paginate/array.rb16
-rw-r--r--vendor/plugins/will_paginate/lib/will_paginate/collection.rb146
-rw-r--r--vendor/plugins/will_paginate/lib/will_paginate/core_ext.rb32
-rw-r--r--vendor/plugins/will_paginate/lib/will_paginate/finder.rb264
-rw-r--r--vendor/plugins/will_paginate/lib/will_paginate/named_scope.rb170
-rw-r--r--vendor/plugins/will_paginate/lib/will_paginate/named_scope_patch.rb37
-rw-r--r--vendor/plugins/will_paginate/lib/will_paginate/version.rb9
-rw-r--r--vendor/plugins/will_paginate/lib/will_paginate/view_helpers.rb389
-rw-r--r--vendor/plugins/will_paginate/test/boot.rb21
-rw-r--r--vendor/plugins/will_paginate/test/collection_test.rb143
-rwxr-xr-xvendor/plugins/will_paginate/test/console8
-rw-r--r--vendor/plugins/will_paginate/test/finder_test.rb476
-rw-r--r--vendor/plugins/will_paginate/test/fixtures/admin.rb3
-rw-r--r--vendor/plugins/will_paginate/test/fixtures/developer.rb14
-rw-r--r--vendor/plugins/will_paginate/test/fixtures/developers_projects.yml13
-rw-r--r--vendor/plugins/will_paginate/test/fixtures/project.rb15
-rw-r--r--vendor/plugins/will_paginate/test/fixtures/projects.yml6
-rw-r--r--vendor/plugins/will_paginate/test/fixtures/replies.yml29
-rw-r--r--vendor/plugins/will_paginate/test/fixtures/reply.rb7
-rw-r--r--vendor/plugins/will_paginate/test/fixtures/topic.rb10
-rw-r--r--vendor/plugins/will_paginate/test/fixtures/topics.yml30
-rw-r--r--vendor/plugins/will_paginate/test/fixtures/user.rb2
-rw-r--r--vendor/plugins/will_paginate/test/fixtures/users.yml35
-rw-r--r--vendor/plugins/will_paginate/test/helper.rb37
-rw-r--r--vendor/plugins/will_paginate/test/lib/activerecord_test_case.rb36
-rw-r--r--vendor/plugins/will_paginate/test/lib/activerecord_test_connector.rb75
-rw-r--r--vendor/plugins/will_paginate/test/lib/load_fixtures.rb11
-rw-r--r--vendor/plugins/will_paginate/test/lib/view_test_process.rb171
-rw-r--r--vendor/plugins/will_paginate/test/tasks.rake59
-rw-r--r--vendor/plugins/will_paginate/test/view_test.rb365
-rw-r--r--vendor/plugins/will_paginate/will_paginate.gemspec20
44 files changed, 3420 insertions, 0 deletions
diff --git a/vendor/plugins/will_paginate/.gitignore b/vendor/plugins/will_paginate/.gitignore
new file mode 100644
index 0000000..2b437b9
--- /dev/null
+++ b/vendor/plugins/will_paginate/.gitignore
@@ -0,0 +1,4 @@
1/doc
2/rails
3*.gem
4/coverage
diff --git a/vendor/plugins/will_paginate/.manifest b/vendor/plugins/will_paginate/.manifest
new file mode 100644
index 0000000..cda4af44
--- /dev/null
+++ b/vendor/plugins/will_paginate/.manifest
@@ -0,0 +1,49 @@
1CHANGELOG.rdoc
2LICENSE
3README.rdoc
4Rakefile
5examples
6examples/apple-circle.gif
7examples/index.haml
8examples/index.html
9examples/pagination.css
10examples/pagination.sass
11init.rb
12lib
13lib/will_paginate
14lib/will_paginate.rb
15lib/will_paginate/array.rb
16lib/will_paginate/collection.rb
17lib/will_paginate/core_ext.rb
18lib/will_paginate/finder.rb
19lib/will_paginate/named_scope.rb
20lib/will_paginate/named_scope_patch.rb
21lib/will_paginate/version.rb
22lib/will_paginate/view_helpers.rb
23test
24test/boot.rb
25test/collection_test.rb
26test/console
27test/database.yml
28test/finder_test.rb
29test/fixtures
30test/fixtures/admin.rb
31test/fixtures/developer.rb
32test/fixtures/developers_projects.yml
33test/fixtures/project.rb
34test/fixtures/projects.yml
35test/fixtures/replies.yml
36test/fixtures/reply.rb
37test/fixtures/schema.rb
38test/fixtures/topic.rb
39test/fixtures/topics.yml
40test/fixtures/user.rb
41test/fixtures/users.yml
42test/helper.rb
43test/lib
44test/lib/activerecord_test_case.rb
45test/lib/activerecord_test_connector.rb
46test/lib/load_fixtures.rb
47test/lib/view_test_process.rb
48test/tasks.rake
49test/view_test.rb \ No newline at end of file
diff --git a/vendor/plugins/will_paginate/CHANGELOG.rdoc b/vendor/plugins/will_paginate/CHANGELOG.rdoc
new file mode 100644
index 0000000..01aea3a
--- /dev/null
+++ b/vendor/plugins/will_paginate/CHANGELOG.rdoc
@@ -0,0 +1,110 @@
1== 2.3.6, released 2008-10-26
2
3* Rails 2.2 fix: stop using `extract_attribute_names_from_match` inernal AR method, it no longer exists
4
5== 2.3.5, released 2008-10-07
6
7* update the backported named_scope implementation for Rails versions older than 2.1
8* break out of scope of paginated_each() yielded block when used on named scopes
9* fix paginate(:from)
10
11== 2.3.4, released 2008-09-16
12
13* Removed gem dependency to Active Support (causes trouble with vendored rails).
14* Rails 2.1: fix a failing test and a deprecation warning.
15* Cope with scoped :select when counting.
16
17== 2.3.3, released 2008-08-29
18
19* Ensure that paginate_by_sql doesn't change the original SQL query.
20* RDoc love (now live at http://mislav.caboo.se/static/will_paginate/doc/)
21* Rename :prev_label to :previous_label for consistency. old name still functions but is deprecated
22* ActiveRecord 2.1: Remove :include option from count_all query when it's possible.
23
24== 2.3.2, released 2008-05-16
25
26* Fixed LinkRenderer#stringified_merge by removing "return" from iterator block
27* Ensure that 'href' values in pagination links are escaped URLs
28
29== 2.3.1, released 2008-05-04
30
31* Fixed page numbers not showing with custom routes and implicit first page
32* Try to use Hanna for documentation (falls back to default RDoc template if not)
33
34== 2.3.0, released 2008-04-29
35
36* Changed LinkRenderer to receive collection, options and reference to view template NOT in
37 constructor, but with the #prepare method. This is a step towards supporting passing of
38 LinkRenderer (or subclass) instances that may be preconfigured in some way
39* LinkRenderer now has #page_link and #page_span methods for easier customization of output in
40 subclasses
41* Changed page_entries_info() method to adjust its output according to humanized class name of
42 collection items. Override this with :entry_name parameter (singular).
43
44 page_entries_info(@posts)
45 #-> "Displaying all 12 posts"
46 page_entries_info(@posts, :entry_name => 'item')
47 #-> "Displaying all 12 items"
48
49== 2.2.3, released 2008-04-26
50
51* will_paginate gem is no longer published on RubyForge, but on
52 gems.github.com:
53
54 gem sources -a http://gems.github.com/ (you only need to do this once)
55 gem install mislav-will_paginate
56
57* extract reusable pagination testing stuff into WillPaginate::View
58* rethink the page URL construction mechanizm to be more bulletproof when
59 combined with custom routing for page parameter
60* test that anchor parameter can be used in pagination links
61
62== 2.2.2, released 2008-04-21
63
64* Add support for page parameter in custom routes like "/foo/page/2"
65* Change output of "page_entries_info" on single-page collection and erraneous
66 output with empty collection as reported by Tim Chater
67
68== 2.2.1, released 2008-04-08
69
70* take less risky path when monkeypatching named_scope; fix that it no longer
71 requires ActiveRecord::VERSION
72* use strings in "respond_to?" calls to work around a bug in acts_as_ferret
73 stable (ugh)
74* add rake release task
75
76
77== 2.2.0, released 2008-04-07
78
79=== API changes
80* Rename WillPaginate::Collection#page_count to "total_pages" for consistency.
81 If you implemented this interface, change your implementation accordingly.
82* Remove old, deprecated style of calling Array#paginate as "paginate(page,
83 per_page)". If you want to specify :page, :per_page or :total_entries, use a
84 parameter hash.
85* Rename LinkRenderer#url_options to "url_for" and drastically optimize it
86
87=== View changes
88* Added "prev_page" and "next_page" CSS classes on previous/next page buttons
89* Add examples of pagination links styling in "examples/index.html"
90* Change gap in pagination links from "..." to
91 "<span class="gap">&hellip;</span>".
92* Add "paginated_section", a block helper that renders pagination both above and
93 below content in the block
94* Add rel="prev|next|start" to page links
95
96=== Other
97
98* Add ability to opt-in for Rails 2.1 feature "named_scope" by calling
99 WillPaginate.enable_named_scope (tested in Rails 1.2.6 and 2.0.2)
100* Support complex page parameters like "developers[page]"
101* Move Array#paginate definition to will_paginate/array.rb. You can now easily
102 use pagination on arrays outside of Rails:
103
104 gem 'will_paginate'
105 require 'will_paginate/array'
106
107* Add "paginated_each" method for iterating through every record by loading only
108 one page of records at the time
109* Rails 2: Rescue from WillPaginate::InvalidPage error with 404 Not Found by
110 default
diff --git a/vendor/plugins/will_paginate/LICENSE b/vendor/plugins/will_paginate/LICENSE
new file mode 100644
index 0000000..96a48cb
--- /dev/null
+++ b/vendor/plugins/will_paginate/LICENSE
@@ -0,0 +1,18 @@
1Copyright (c) 2007 PJ Hyett and Mislav Marohnić
2
3Permission is hereby granted, free of charge, to any person obtaining a copy of
4this software and associated documentation files (the "Software"), to deal in
5the Software without restriction, including without limitation the rights to
6use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
7the Software, and to permit persons to whom the Software is furnished to do so,
8subject to the following conditions:
9
10The above copyright notice and this permission notice shall be included in all
11copies or substantial portions of the Software.
12
13THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
15FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
16COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
17IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
18CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/vendor/plugins/will_paginate/README.rdoc b/vendor/plugins/will_paginate/README.rdoc
new file mode 100644
index 0000000..2a412f5
--- /dev/null
+++ b/vendor/plugins/will_paginate/README.rdoc
@@ -0,0 +1,107 @@
1= WillPaginate
2
3Pagination is just limiting the number of records displayed. Why should you let
4it get in your way while developing, then? This plugin makes magic happen. Did
5you ever want to be able to do just this on a model:
6
7 Post.paginate :page => 1, :order => 'created_at DESC'
8
9... and then render the page links with a single view helper? Well, now you
10can.
11
12Some resources to get you started:
13
14* {Installation instructions}[http://github.com/mislav/will_paginate/wikis/installation]
15 on {the wiki}[http://github.com/mislav/will_paginate/wikis]
16* Your mind reels with questions? Join our
17 {Google group}[http://groups.google.com/group/will_paginate].
18* {How to report bugs}[http://github.com/mislav/will_paginate/wikis/report-bugs]
19
20
21== Example usage
22
23Use a paginate finder in the controller:
24
25 @posts = Post.paginate_by_board_id @board.id, :page => params[:page], :order => 'updated_at DESC'
26
27Yeah, +paginate+ works just like +find+ -- it just doesn't fetch all the
28records. Don't forget to tell it which page you want, or it will complain!
29Read more on WillPaginate::Finder::ClassMethods.
30
31Render the posts in your view like you would normally do. When you need to render
32pagination, just stick this in:
33
34 <%= will_paginate @posts %>
35
36You're done. (You can find the option list at WillPaginate::ViewHelpers.)
37
38How does it know how much items to fetch per page? It asks your model by calling
39its <tt>per_page</tt> class method. You can define it like this:
40
41 class Post < ActiveRecord::Base
42 cattr_reader :per_page
43 @@per_page = 50
44 end
45
46... or like this:
47
48 class Post < ActiveRecord::Base
49 def self.per_page
50 50
51 end
52 end
53
54... or don't worry about it at all. WillPaginate defines it to be <b>30</b> by default.
55But you can always specify the count explicitly when calling +paginate+:
56
57 @posts = Post.paginate :page => params[:page], :per_page => 50
58
59The +paginate+ finder wraps the original finder and returns your resultset that now has
60some new properties. You can use the collection as you would with any ActiveRecord
61resultset. WillPaginate view helpers also need that object to be able to render pagination:
62
63 <ol>
64 <% for post in @posts -%>
65 <li>Render `post` in some nice way.</li>
66 <% end -%>
67 </ol>
68
69 <p>Now let's render us some pagination!</p>
70 <%= will_paginate @posts %>
71
72More detailed documentation:
73
74* WillPaginate::Finder::ClassMethods for pagination on your models;
75* WillPaginate::ViewHelpers for your views.
76
77
78== Authors and credits
79
80Authors:: Mislav Marohnić, PJ Hyett
81Original announcement:: http://errtheblog.com/post/929
82Original PHP source:: http://www.strangerstudios.com/sandbox/pagination/diggstyle.php
83
84All these people helped making will_paginate what it is now with their code
85contributions or just simply awesome ideas:
86
87Chris Wanstrath, Dr. Nic Williams, K. Adam Christensen, Mike Garey, Bence
88Golda, Matt Aimonetti, Charles Brian Quinn, Desi McAdam, James Coglan, Matijs
89van Zuijlen, Maria, Brendan Ribera, Todd Willey, Bryan Helmkamp, Jan Berkel,
90Lourens Naudé, Rick Olson, Russell Norris, Piotr Usewicz, Chris Eppstein,
91Denis Barushev, Ben Pickles.
92
93
94== Usable pagination in the UI
95
96There are some CSS styles to get you started in the "examples/" directory. They
97are {showcased online here}[http://mislav.caboo.se/static/will_paginate/].
98
99More reading about pagination as design pattern:
100
101* {Pagination 101}[http://kurafire.net/log/archive/2007/06/22/pagination-101]
102* {Pagination gallery}[http://www.smashingmagazine.com/2007/11/16/pagination-gallery-examples-and-good-practices/]
103* {Pagination on Yahoo Design Pattern Library}[http://developer.yahoo.com/ypatterns/parent.php?pattern=pagination]
104
105Want to discuss, request features, ask questions? Join the
106{Google group}[http://groups.google.com/group/will_paginate].
107
diff --git a/vendor/plugins/will_paginate/Rakefile b/vendor/plugins/will_paginate/Rakefile
new file mode 100644
index 0000000..253efd0
--- /dev/null
+++ b/vendor/plugins/will_paginate/Rakefile
@@ -0,0 +1,62 @@
1require 'rubygems'
2begin
3 hanna_dir = '/Users/mislav/Projects/Hanna/lib'
4 $:.unshift hanna_dir if File.exists? hanna_dir
5 require 'hanna/rdoctask'
6rescue LoadError
7 require 'rake'
8 require 'rake/rdoctask'
9end
10load 'test/tasks.rake'
11
12desc 'Default: run unit tests.'
13task :default => :test
14
15desc 'Generate RDoc documentation for the will_paginate plugin.'
16Rake::RDocTask.new(:rdoc) do |rdoc|
17 rdoc.rdoc_files.include('README.rdoc', 'LICENSE', 'CHANGELOG.rdoc').
18 include('lib/**/*.rb').
19 exclude('lib/will_paginate/named_scope*').
20 exclude('lib/will_paginate/array.rb').
21 exclude('lib/will_paginate/version.rb')
22
23 rdoc.main = "README.rdoc" # page to start on
24 rdoc.title = "will_paginate documentation"
25
26 rdoc.rdoc_dir = 'doc' # rdoc output folder
27 rdoc.options << '--inline-source' << '--charset=UTF-8'
28 rdoc.options << '--webcvs=http://github.com/mislav/will_paginate/tree/master/'
29end
30
31desc %{Update ".manifest" with the latest list of project filenames. Respect\
32.gitignore by excluding everything that git ignores. Update `files` and\
33`test_files` arrays in "*.gemspec" file if it's present.}
34task :manifest do
35 list = Dir['**/*'].sort
36 spec_file = Dir['*.gemspec'].first
37 list -= [spec_file] if spec_file
38
39 File.read('.gitignore').each_line do |glob|
40 glob = glob.chomp.sub(/^\//, '')
41 list -= Dir[glob]
42 list -= Dir["#{glob}/**/*"] if File.directory?(glob) and !File.symlink?(glob)
43 puts "excluding #{glob}"
44 end
45
46 if spec_file
47 spec = File.read spec_file
48 spec.gsub! /^(\s* s.(test_)?files \s* = \s* )( \[ [^\]]* \] | %w\( [^)]* \) )/mx do
49 assignment = $1
50 bunch = $2 ? list.grep(/^test\//) : list
51 '%s%%w(%s)' % [assignment, bunch.join(' ')]
52 end
53
54 File.open(spec_file, 'w') {|f| f << spec }
55 end
56 File.open('.manifest', 'w') {|f| f << list.join("\n") }
57end
58
59task :examples do
60 %x(haml examples/index.haml examples/index.html)
61 %x(sass examples/pagination.sass examples/pagination.css)
62end
diff --git a/vendor/plugins/will_paginate/examples/apple-circle.gif b/vendor/plugins/will_paginate/examples/apple-circle.gif
new file mode 100644
index 0000000..df8cbf7
--- /dev/null
+++ b/vendor/plugins/will_paginate/examples/apple-circle.gif
Binary files differ
diff --git a/vendor/plugins/will_paginate/examples/index.haml b/vendor/plugins/will_paginate/examples/index.haml
new file mode 100644
index 0000000..fb41ac8
--- /dev/null
+++ b/vendor/plugins/will_paginate/examples/index.haml
@@ -0,0 +1,69 @@
1!!!
2%html
3%head
4 %title Samples of pagination styling for will_paginate
5 %link{ :rel => 'stylesheet', :type => 'text/css', :href => 'pagination.css' }
6 %style{ :type => 'text/css' }
7 :sass
8 html
9 :margin 0
10 :padding 0
11 :background #999
12 :font normal 76% "Lucida Grande", Verdana, Helvetica, sans-serif
13 body
14 :margin 2em
15 :padding 2em
16 :border 2px solid gray
17 :background white
18 :color #222
19 h1
20 :font-size 2em
21 :font-weight normal
22 :margin 0 0 1em 0
23 h2
24 :font-size 1.4em
25 :margin 1em 0 .5em 0
26 pre
27 :font-size 13px
28 :font-family Monaco, "DejaVu Sans Mono", "Bitstream Vera Mono", "Courier New", monospace
29
30- pagination = '<span class="disabled prev_page">&laquo; Previous</span> <span class="current">1</span> <a href="./?page=2" rel="next">2</a> <a href="./?page=3">3</a> <a href="./?page=4">4</a> <a href="./?page=5">5</a> <a href="./?page=6">6</a> <a href="./?page=7">7</a> <a href="./?page=8">8</a> <a href="./?page=9">9</a> <span class="gap">&hellip;</span> <a href="./?page=29">29</a> <a href="./?page=30">30</a> <a href="./?page=2" rel="next" class="next_page">Next &raquo;</a>'
31- pagination_no_page_links = '<span class="disabled prev_page">&laquo; Previous</span> <a href="./?page=2" rel="next" class="next_page">Next &raquo;</a>'
32
33%body
34 %h1 Samples of pagination styling for will_paginate
35 %p
36 Find these styles in <b>"examples/pagination.css"</b> of <i>will_paginate</i> library.
37 There is a Sass version of it for all you sassy people.
38 %p
39 Read about good rules for pagination:
40 %a{ :href => 'http://kurafire.net/log/archive/2007/06/22/pagination-101' } Pagination 101
41 %p
42 %em Warning:
43 page links below don't lead anywhere (so don't click on them).
44
45 %h2 Unstyled pagination <span style="font-weight:normal">(<i>ewww!</i>)</span>
46 %div= pagination
47
48 %h2 Digg.com
49 .digg_pagination= pagination
50
51 %h2 Digg-style, no page links
52 .digg_pagination= pagination_no_page_links
53 %p Code that renders this:
54 %pre= '<code>%s</code>' % %[<%= will_paginate @posts, :page_links => false %>].gsub('<', '&lt;').gsub('>', '&gt;')
55
56 %h2 Digg-style, extra content
57 .digg_pagination
58 .page_info Displaying entries <b>1&nbsp;-&nbsp;6</b> of <b>180</b> in total
59 = pagination
60 %p Code that renders this:
61 %pre= '<code>%s</code>' % %[<div class="digg_pagination">\n <div clas="page_info">\n <%= page_entries_info @posts %>\n </div>\n <%= will_paginate @posts, :container => false %>\n</div>].gsub('<', '&lt;').gsub('>', '&gt;')
62
63 %h2 Apple.com store
64 .apple_pagination= pagination
65
66 %h2 Flickr.com
67 .flickr_pagination
68 = pagination
69 .page_info (118 photos)
diff --git a/vendor/plugins/will_paginate/examples/index.html b/vendor/plugins/will_paginate/examples/index.html
new file mode 100644
index 0000000..858f7c6
--- /dev/null
+++ b/vendor/plugins/will_paginate/examples/index.html
@@ -0,0 +1,92 @@
1<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
2<html>
3</html>
4<head>
5 <title>Samples of pagination styling for will_paginate</title>
6 <link href='pagination.css' rel='stylesheet' type='text/css' />
7 <style type='text/css'>
8 html {
9 margin: 0;
10 padding: 0;
11 background: #999;
12 font: normal 76% "Lucida Grande", Verdana, Helvetica, sans-serif; }
13
14 body {
15 margin: 2em;
16 padding: 2em;
17 border: 2px solid gray;
18 background: white;
19 color: #222; }
20
21 h1 {
22 font-size: 2em;
23 font-weight: normal;
24 margin: 0 0 1em 0; }
25
26 h2 {
27 font-size: 1.4em;
28 margin: 1em 0 .5em 0; }
29
30 pre {
31 font-size: 13px;
32 font-family: Monaco, "DejaVu Sans Mono", "Bitstream Vera Mono", "Courier New", monospace; }
33 </style>
34</head>
35<body>
36 <h1>Samples of pagination styling for will_paginate</h1>
37 <p>
38 Find these styles in <b>"examples/pagination.css"</b> of <i>will_paginate</i> library.
39 There is a Sass version of it for all you sassy people.
40 </p>
41 <p>
42 Read about good rules for pagination:
43 <a href='http://kurafire.net/log/archive/2007/06/22/pagination-101'>Pagination 101</a>
44 </p>
45 <p>
46 <em>Warning:</em>
47 page links below don't lead anywhere (so don't click on them).
48 </p>
49 <h2>
50 Unstyled pagination <span style="font-weight:normal">(<i>ewww!</i>)</span>
51 </h2>
52 <div>
53 <span class="disabled prev_page">&laquo; Previous</span> <span class="current">1</span> <a href="./?page=2" rel="next">2</a> <a href="./?page=3">3</a> <a href="./?page=4">4</a> <a href="./?page=5">5</a> <a href="./?page=6">6</a> <a href="./?page=7">7</a> <a href="./?page=8">8</a> <a href="./?page=9">9</a> <span class="gap">&hellip;</span> <a href="./?page=29">29</a> <a href="./?page=30">30</a> <a href="./?page=2" rel="next" class="next_page">Next &raquo;</a>
54 </div>
55 <h2>Digg.com</h2>
56 <div class='digg_pagination'>
57 <span class="disabled prev_page">&laquo; Previous</span> <span class="current">1</span> <a href="./?page=2" rel="next">2</a> <a href="./?page=3">3</a> <a href="./?page=4">4</a> <a href="./?page=5">5</a> <a href="./?page=6">6</a> <a href="./?page=7">7</a> <a href="./?page=8">8</a> <a href="./?page=9">9</a> <span class="gap">&hellip;</span> <a href="./?page=29">29</a> <a href="./?page=30">30</a> <a href="./?page=2" rel="next" class="next_page">Next &raquo;</a>
58 </div>
59 <h2>Digg-style, no page links</h2>
60 <div class='digg_pagination'>
61 <span class="disabled prev_page">&laquo; Previous</span> <a href="./?page=2" rel="next" class="next_page">Next &raquo;</a>
62 </div>
63 <p>Code that renders this:</p>
64 <pre>
65 <code>&lt;%= will_paginate @posts, :page_links =&gt; false %&gt;</code>
66 </pre>
67 <h2>Digg-style, extra content</h2>
68 <div class='digg_pagination'>
69 <div class='page_info'>
70 Displaying entries <b>1&nbsp;-&nbsp;6</b> of <b>180</b> in total
71 </div>
72 <span class="disabled prev_page">&laquo; Previous</span> <span class="current">1</span> <a href="./?page=2" rel="next">2</a> <a href="./?page=3">3</a> <a href="./?page=4">4</a> <a href="./?page=5">5</a> <a href="./?page=6">6</a> <a href="./?page=7">7</a> <a href="./?page=8">8</a> <a href="./?page=9">9</a> <span class="gap">&hellip;</span> <a href="./?page=29">29</a> <a href="./?page=30">30</a> <a href="./?page=2" rel="next" class="next_page">Next &raquo;</a>
73 </div>
74 <p>Code that renders this:</p>
75 <pre>
76 <code>&lt;div class="digg_pagination"&gt;
77 &lt;div clas="page_info"&gt;
78 &lt;%= page_entries_info @posts %&gt;
79 &lt;/div&gt;
80 &lt;%= will_paginate @posts, :container =&gt; false %&gt;
81 &lt;/div&gt;</code>
82 </pre>
83 <h2>Apple.com store</h2>
84 <div class='apple_pagination'>
85 <span class="disabled prev_page">&laquo; Previous</span> <span class="current">1</span> <a href="./?page=2" rel="next">2</a> <a href="./?page=3">3</a> <a href="./?page=4">4</a> <a href="./?page=5">5</a> <a href="./?page=6">6</a> <a href="./?page=7">7</a> <a href="./?page=8">8</a> <a href="./?page=9">9</a> <span class="gap">&hellip;</span> <a href="./?page=29">29</a> <a href="./?page=30">30</a> <a href="./?page=2" rel="next" class="next_page">Next &raquo;</a>
86 </div>
87 <h2>Flickr.com</h2>
88 <div class='flickr_pagination'>
89 <span class="disabled prev_page">&laquo; Previous</span> <span class="current">1</span> <a href="./?page=2" rel="next">2</a> <a href="./?page=3">3</a> <a href="./?page=4">4</a> <a href="./?page=5">5</a> <a href="./?page=6">6</a> <a href="./?page=7">7</a> <a href="./?page=8">8</a> <a href="./?page=9">9</a> <span class="gap">&hellip;</span> <a href="./?page=29">29</a> <a href="./?page=30">30</a> <a href="./?page=2" rel="next" class="next_page">Next &raquo;</a>
90 <div class='page_info'>(118 photos)</div>
91 </div>
92</body>
diff --git a/vendor/plugins/will_paginate/examples/pagination.css b/vendor/plugins/will_paginate/examples/pagination.css
new file mode 100644
index 0000000..b55e977
--- /dev/null
+++ b/vendor/plugins/will_paginate/examples/pagination.css
@@ -0,0 +1,90 @@
1.digg_pagination {
2 background: white;
3 /* self-clearing method: */ }
4 .digg_pagination a, .digg_pagination span {
5 padding: .2em .5em;
6 display: block;
7 float: left;
8 margin-right: 1px; }
9 .digg_pagination span.disabled {
10 color: #999;
11 border: 1px solid #DDD; }
12 .digg_pagination span.current {
13 font-weight: bold;
14 background: #2E6AB1;
15 color: white;
16 border: 1px solid #2E6AB1; }
17 .digg_pagination a {
18 text-decoration: none;
19 color: #105CB6;
20 border: 1px solid #9AAFE5; }
21 .digg_pagination a:hover, .digg_pagination a:focus {
22 color: #003;
23 border-color: #003; }
24 .digg_pagination .page_info {
25 background: #2E6AB1;
26 color: white;
27 padding: .4em .6em;
28 width: 22em;
29 margin-bottom: .3em;
30 text-align: center; }
31 .digg_pagination .page_info b {
32 color: #003;
33 background: #6aa6ed;
34 padding: .1em .25em; }
35 .digg_pagination:after {
36 content: ".";
37 display: block;
38 height: 0;
39 clear: both;
40 visibility: hidden; }
41 * html .digg_pagination {
42 height: 1%; }
43 *:first-child+html .digg_pagination {
44 overflow: hidden; }
45
46.apple_pagination {
47 background: #F1F1F1;
48 border: 1px solid #E5E5E5;
49 text-align: center;
50 padding: 1em; }
51 .apple_pagination a, .apple_pagination span {
52 padding: .2em .3em; }
53 .apple_pagination span.disabled {
54 color: #AAA; }
55 .apple_pagination span.current {
56 font-weight: bold;
57 background: transparent url(apple-circle.gif) no-repeat 50% 50%; }
58 .apple_pagination a {
59 text-decoration: none;
60 color: black; }
61 .apple_pagination a:hover, .apple_pagination a:focus {
62 text-decoration: underline; }
63
64.flickr_pagination {
65 text-align: center;
66 padding: .3em; }
67 .flickr_pagination a, .flickr_pagination span {
68 padding: .2em .5em; }
69 .flickr_pagination span.disabled {
70 color: #AAA; }
71 .flickr_pagination span.current {
72 font-weight: bold;
73 color: #FF0084; }
74 .flickr_pagination a {
75 border: 1px solid #DDDDDD;
76 color: #0063DC;
77 text-decoration: none; }
78 .flickr_pagination a:hover, .flickr_pagination a:focus {
79 border-color: #003366;
80 background: #0063DC;
81 color: white; }
82 .flickr_pagination .page_info {
83 color: #aaa;
84 padding-top: .8em; }
85 .flickr_pagination .prev_page, .flickr_pagination .next_page {
86 border-width: 2px; }
87 .flickr_pagination .prev_page {
88 margin-right: 1em; }
89 .flickr_pagination .next_page {
90 margin-left: 1em; }
diff --git a/vendor/plugins/will_paginate/examples/pagination.sass b/vendor/plugins/will_paginate/examples/pagination.sass
new file mode 100644
index 0000000..737a97b
--- /dev/null
+++ b/vendor/plugins/will_paginate/examples/pagination.sass
@@ -0,0 +1,91 @@
1.digg_pagination
2 :background white
3 a, span
4 :padding .2em .5em
5 :display block
6 :float left
7 :margin-right 1px
8 span.disabled
9 :color #999
10 :border 1px solid #DDD
11 span.current
12 :font-weight bold
13 :background #2E6AB1
14 :color white
15 :border 1px solid #2E6AB1
16 a
17 :text-decoration none
18 :color #105CB6
19 :border 1px solid #9AAFE5
20 &:hover, &:focus
21 :color #003
22 :border-color #003
23 .page_info
24 :background #2E6AB1
25 :color white
26 :padding .4em .6em
27 :width 22em
28 :margin-bottom .3em
29 :text-align center
30 b
31 :color #003
32 :background = #2E6AB1 + 60
33 :padding .1em .25em
34
35 /* self-clearing method:
36 &:after
37 :content "."
38 :display block
39 :height 0
40 :clear both
41 :visibility hidden
42 * html &
43 :height 1%
44 *:first-child+html &
45 :overflow hidden
46
47.apple_pagination
48 :background #F1F1F1
49 :border 1px solid #E5E5E5
50 :text-align center
51 :padding 1em
52 a, span
53 :padding .2em .3em
54 span.disabled
55 :color #AAA
56 span.current
57 :font-weight bold
58 :background transparent url(apple-circle.gif) no-repeat 50% 50%
59 a
60 :text-decoration none
61 :color black
62 &:hover, &:focus
63 :text-decoration underline
64
65.flickr_pagination
66 :text-align center
67 :padding .3em
68 a, span
69 :padding .2em .5em
70 span.disabled
71 :color #AAA
72 span.current
73 :font-weight bold
74 :color #FF0084
75 a
76 :border 1px solid #DDDDDD
77 :color #0063DC
78 :text-decoration none
79 &:hover, &:focus
80 :border-color #003366
81 :background #0063DC
82 :color white
83 .page_info
84 :color #aaa
85 :padding-top .8em
86 .prev_page, .next_page
87 :border-width 2px
88 .prev_page
89 :margin-right 1em
90 .next_page
91 :margin-left 1em
diff --git a/vendor/plugins/will_paginate/init.rb b/vendor/plugins/will_paginate/init.rb
new file mode 100644
index 0000000..838d30e
--- /dev/null
+++ b/vendor/plugins/will_paginate/init.rb
@@ -0,0 +1 @@
require 'will_paginate'
diff --git a/vendor/plugins/will_paginate/lib/will_paginate.rb b/vendor/plugins/will_paginate/lib/will_paginate.rb
new file mode 100644
index 0000000..e072412
--- /dev/null
+++ b/vendor/plugins/will_paginate/lib/will_paginate.rb
@@ -0,0 +1,78 @@
1require 'active_support'
2
3# = You *will* paginate!
4#
5# First read about WillPaginate::Finder::ClassMethods, then see
6# WillPaginate::ViewHelpers. The magical array you're handling in-between is
7# WillPaginate::Collection.
8#
9# Happy paginating!
10module WillPaginate
11 class << self
12 # shortcut for <tt>enable_actionpack</tt> and <tt>enable_activerecord</tt> combined
13 def enable
14 enable_actionpack
15 enable_activerecord
16 end
17
18 # hooks WillPaginate::ViewHelpers into ActionView::Base
19 def enable_actionpack
20 return if ActionView::Base.instance_methods.include? 'will_paginate'
21 require 'will_paginate/view_helpers'
22 ActionView::Base.send :include, ViewHelpers
23
24 if defined?(ActionController::Base) and ActionController::Base.respond_to? :rescue_responses
25 ActionController::Base.rescue_responses['WillPaginate::InvalidPage'] = :not_found
26 end
27 end
28
29 # hooks WillPaginate::Finder into ActiveRecord::Base and classes that deal
30 # with associations
31 def enable_activerecord
32 return if ActiveRecord::Base.respond_to? :paginate
33 require 'will_paginate/finder'
34 ActiveRecord::Base.send :include, Finder
35
36 # support pagination on associations
37 a = ActiveRecord::Associations
38 returning([ a::AssociationCollection ]) { |classes|
39 # detect http://dev.rubyonrails.org/changeset/9230
40 unless a::HasManyThroughAssociation.superclass == a::HasManyAssociation
41 classes << a::HasManyThroughAssociation
42 end
43 }.each do |klass|
44 klass.send :include, Finder::ClassMethods
45 klass.class_eval { alias_method_chain :method_missing, :paginate }
46 end
47 end
48
49 # Enable named_scope, a feature of Rails 2.1, even if you have older Rails
50 # (tested on Rails 2.0.2 and 1.2.6).
51 #
52 # You can pass +false+ for +patch+ parameter to skip monkeypatching
53 # *associations*. Use this if you feel that <tt>named_scope</tt> broke
54 # has_many, has_many :through or has_and_belongs_to_many associations in
55 # your app. By passing +false+, you can still use <tt>named_scope</tt> in
56 # your models, but not through associations.
57 def enable_named_scope(patch = true)
58 return if defined? ActiveRecord::NamedScope
59 require 'will_paginate/named_scope'
60 require 'will_paginate/named_scope_patch' if patch
61
62 ActiveRecord::Base.send :include, WillPaginate::NamedScope
63 end
64 end
65
66 module Deprecation # :nodoc:
67 extend ActiveSupport::Deprecation
68
69 def self.warn(message, callstack = caller)
70 message = 'WillPaginate: ' + message.strip.gsub(/\s+/, ' ')
71 ActiveSupport::Deprecation.warn(message, callstack)
72 end
73 end
74end
75
76if defined?(Rails) and defined?(ActiveRecord) and defined?(ActionController)
77 WillPaginate.enable
78end
diff --git a/vendor/plugins/will_paginate/lib/will_paginate/array.rb b/vendor/plugins/will_paginate/lib/will_paginate/array.rb
new file mode 100644
index 0000000..d061d2b
--- /dev/null
+++ b/vendor/plugins/will_paginate/lib/will_paginate/array.rb
@@ -0,0 +1,16 @@
1require 'will_paginate/collection'
2
3# http://www.desimcadam.com/archives/8
4Array.class_eval do
5 def paginate(options = {})
6 raise ArgumentError, "parameter hash expected (got #{options.inspect})" unless Hash === options
7
8 WillPaginate::Collection.create(
9 options[:page] || 1,
10 options[:per_page] || 30,
11 options[:total_entries] || self.length
12 ) { |pager|
13 pager.replace self[pager.offset, pager.per_page].to_a
14 }
15 end
16end
diff --git a/vendor/plugins/will_paginate/lib/will_paginate/collection.rb b/vendor/plugins/will_paginate/lib/will_paginate/collection.rb
new file mode 100644
index 0000000..e253570
--- /dev/null
+++ b/vendor/plugins/will_paginate/lib/will_paginate/collection.rb
@@ -0,0 +1,146 @@
1module WillPaginate
2 # = Invalid page number error
3 # This is an ArgumentError raised in case a page was requested that is either
4 # zero or negative number. You should decide how do deal with such errors in
5 # the controller.
6 #
7 # If you're using Rails 2, then this error will automatically get handled like
8 # 404 Not Found. The hook is in "will_paginate.rb":
9 #
10 # ActionController::Base.rescue_responses['WillPaginate::InvalidPage'] = :not_found
11 #
12 # If you don't like this, use your preffered method of rescuing exceptions in
13 # public from your controllers to handle this differently. The +rescue_from+
14 # method is a nice addition to Rails 2.
15 #
16 # This error is *not* raised when a page further than the last page is
17 # requested. Use <tt>WillPaginate::Collection#out_of_bounds?</tt> method to
18 # check for those cases and manually deal with them as you see fit.
19 class InvalidPage < ArgumentError
20 def initialize(page, page_num)
21 super "#{page.inspect} given as value, which translates to '#{page_num}' as page number"
22 end
23 end
24
25 # = The key to pagination
26 # Arrays returned from paginating finds are, in fact, instances of this little
27 # class. You may think of WillPaginate::Collection as an ordinary array with
28 # some extra properties. Those properties are used by view helpers to generate
29 # correct page links.
30 #
31 # WillPaginate::Collection also assists in rolling out your own pagination
32 # solutions: see +create+.
33 #
34 # If you are writing a library that provides a collection which you would like
35 # to conform to this API, you don't have to copy these methods over; simply
36 # make your plugin/gem dependant on the "mislav-will_paginate" gem:
37 #
38 # gem 'mislav-will_paginate'
39 # require 'will_paginate/collection'
40 #
41 # # WillPaginate::Collection is now available for use
42 class Collection < Array
43 attr_reader :current_page, :per_page, :total_entries, :total_pages
44
45 # Arguments to the constructor are the current page number, per-page limit
46 # and the total number of entries. The last argument is optional because it
47 # is best to do lazy counting; in other words, count *conditionally* after
48 # populating the collection using the +replace+ method.
49 def initialize(page, per_page, total = nil)
50 @current_page = page.to_i
51 raise InvalidPage.new(page, @current_page) if @current_page < 1
52 @per_page = per_page.to_i
53 raise ArgumentError, "`per_page` setting cannot be less than 1 (#{@per_page} given)" if @per_page < 1
54
55 self.total_entries = total if total
56 end
57
58 # Just like +new+, but yields the object after instantiation and returns it
59 # afterwards. This is very useful for manual pagination:
60 #
61 # @entries = WillPaginate::Collection.create(1, 10) do |pager|
62 # result = Post.find(:all, :limit => pager.per_page, :offset => pager.offset)
63 # # inject the result array into the paginated collection:
64 # pager.replace(result)
65 #
66 # unless pager.total_entries
67 # # the pager didn't manage to guess the total count, do it manually
68 # pager.total_entries = Post.count
69 # end
70 # end
71 #
72 # The possibilities with this are endless. For another example, here is how
73 # WillPaginate used to define pagination for Array instances:
74 #
75 # Array.class_eval do
76 # def paginate(page = 1, per_page = 15)
77 # WillPaginate::Collection.create(page, per_page, size) do |pager|
78 # pager.replace self[pager.offset, pager.per_page].to_a
79 # end
80 # end
81 # end
82 #
83 # The Array#paginate API has since then changed, but this still serves as a
84 # fine example of WillPaginate::Collection usage.
85 def self.create(page, per_page, total = nil)
86 pager = new(page, per_page, total)
87 yield pager
88 pager
89 end
90
91 # Helper method that is true when someone tries to fetch a page with a
92 # larger number than the last page. Can be used in combination with flashes
93 # and redirecting.
94 def out_of_bounds?
95 current_page > total_pages
96 end
97
98 # Current offset of the paginated collection. If we're on the first page,
99 # it is always 0. If we're on the 2nd page and there are 30 entries per page,
100 # the offset is 30. This property is useful if you want to render ordinals
101 # side by side with records in the view: simply start with offset + 1.
102 def offset
103 (current_page - 1) * per_page
104 end
105
106 # current_page - 1 or nil if there is no previous page
107 def previous_page
108 current_page > 1 ? (current_page - 1) : nil
109 end
110
111 # current_page + 1 or nil if there is no next page
112 def next_page
113 current_page < total_pages ? (current_page + 1) : nil
114 end
115
116 # sets the <tt>total_entries</tt> property and calculates <tt>total_pages</tt>
117 def total_entries=(number)
118 @total_entries = number.to_i
119 @total_pages = (@total_entries / per_page.to_f).ceil
120 end
121
122 # This is a magic wrapper for the original Array#replace method. It serves
123 # for populating the paginated collection after initialization.
124 #
125 # Why magic? Because it tries to guess the total number of entries judging
126 # by the size of given array. If it is shorter than +per_page+ limit, then we
127 # know we're on the last page. This trick is very useful for avoiding
128 # unnecessary hits to the database to do the counting after we fetched the
129 # data for the current page.
130 #
131 # However, after using +replace+ you should always test the value of
132 # +total_entries+ and set it to a proper value if it's +nil+. See the example
133 # in +create+.
134 def replace(array)
135 result = super
136
137 # The collection is shorter then page limit? Rejoice, because
138 # then we know that we are on the last page!
139 if total_entries.nil? and length < per_page and (current_page == 1 or length > 0)
140 self.total_entries = offset + length
141 end
142
143 result
144 end
145 end
146end
diff --git a/vendor/plugins/will_paginate/lib/will_paginate/core_ext.rb b/vendor/plugins/will_paginate/lib/will_paginate/core_ext.rb
new file mode 100644
index 0000000..32f10f5
--- /dev/null
+++ b/vendor/plugins/will_paginate/lib/will_paginate/core_ext.rb
@@ -0,0 +1,32 @@
1require 'set'
2require 'will_paginate/array'
3
4unless Hash.instance_methods.include? 'except'
5 Hash.class_eval do
6 # Returns a new hash without the given keys.
7 def except(*keys)
8 rejected = Set.new(respond_to?(:convert_key) ? keys.map { |key| convert_key(key) } : keys)
9 reject { |key,| rejected.include?(key) }
10 end
11
12 # Replaces the hash without only the given keys.
13 def except!(*keys)
14 replace(except(*keys))
15 end
16 end
17end
18
19unless Hash.instance_methods.include? 'slice'
20 Hash.class_eval do
21 # Returns a new hash with only the given keys.
22 def slice(*keys)
23 allowed = Set.new(respond_to?(:convert_key) ? keys.map { |key| convert_key(key) } : keys)
24 reject { |key,| !allowed.include?(key) }
25 end
26
27 # Replaces the hash with only the given keys.
28 def slice!(*keys)
29 replace(slice(*keys))
30 end
31 end
32end
diff --git a/vendor/plugins/will_paginate/lib/will_paginate/finder.rb b/vendor/plugins/will_paginate/lib/will_paginate/finder.rb
new file mode 100644
index 0000000..d0e5668
--- /dev/null
+++ b/vendor/plugins/will_paginate/lib/will_paginate/finder.rb
@@ -0,0 +1,264 @@
1require 'will_paginate/core_ext'
2
3module WillPaginate
4 # A mixin for ActiveRecord::Base. Provides +per_page+ class method
5 # and hooks things up to provide paginating finders.
6 #
7 # Find out more in WillPaginate::Finder::ClassMethods
8 #
9 module Finder
10 def self.included(base)
11 base.extend ClassMethods
12 class << base
13 alias_method_chain :method_missing, :paginate
14 # alias_method_chain :find_every, :paginate
15 define_method(:per_page) { 30 } unless respond_to?(:per_page)
16 end
17 end
18
19 # = Paginating finders for ActiveRecord models
20 #
21 # WillPaginate adds +paginate+, +per_page+ and other methods to
22 # ActiveRecord::Base class methods and associations. It also hooks into
23 # +method_missing+ to intercept pagination calls to dynamic finders such as
24 # +paginate_by_user_id+ and translate them to ordinary finders
25 # (+find_all_by_user_id+ in this case).
26 #
27 # In short, paginating finders are equivalent to ActiveRecord finders; the
28 # only difference is that we start with "paginate" instead of "find" and
29 # that <tt>:page</tt> is required parameter:
30 #
31 # @posts = Post.paginate :all, :page => params[:page], :order => 'created_at DESC'
32 #
33 # In paginating finders, "all" is implicit. There is no sense in paginating
34 # a single record, right? So, you can drop the <tt>:all</tt> argument:
35 #
36 # Post.paginate(...) => Post.find :all
37 # Post.paginate_all_by_something => Post.find_all_by_something
38 # Post.paginate_by_something => Post.find_all_by_something
39 #
40 # == The importance of the <tt>:order</tt> parameter
41 #
42 # In ActiveRecord finders, <tt>:order</tt> parameter specifies columns for
43 # the <tt>ORDER BY</tt> clause in SQL. It is important to have it, since
44 # pagination only makes sense with ordered sets. Without the <tt>ORDER
45 # BY</tt> clause, databases aren't required to do consistent ordering when
46 # performing <tt>SELECT</tt> queries; this is especially true for
47 # PostgreSQL.
48 #
49 # Therefore, make sure you are doing ordering on a column that makes the
50 # most sense in the current context. Make that obvious to the user, also.
51 # For perfomance reasons you will also want to add an index to that column.
52 module ClassMethods
53 # This is the main paginating finder.
54 #
55 # == Special parameters for paginating finders
56 # * <tt>:page</tt> -- REQUIRED, but defaults to 1 if false or nil
57 # * <tt>:per_page</tt> -- defaults to <tt>CurrentModel.per_page</tt> (which is 30 if not overridden)
58 # * <tt>:total_entries</tt> -- use only if you manually count total entries
59 # * <tt>:count</tt> -- additional options that are passed on to +count+
60 # * <tt>:finder</tt> -- name of the ActiveRecord finder used (default: "find")
61 #
62 # All other options (+conditions+, +order+, ...) are forwarded to +find+
63 # and +count+ calls.
64 def paginate(*args)
65 options = args.pop
66 page, per_page, total_entries = wp_parse_options(options)
67 finder = (options[:finder] || 'find').to_s
68
69 if finder == 'find'
70 # an array of IDs may have been given:
71 total_entries ||= (Array === args.first and args.first.size)
72 # :all is implicit
73 args.unshift(:all) if args.empty?
74 end
75
76 WillPaginate::Collection.create(page, per_page, total_entries) do |pager|
77 count_options = options.except :page, :per_page, :total_entries, :finder
78 find_options = count_options.except(:count).update(:offset => pager.offset, :limit => pager.per_page)
79
80 args << find_options
81 # @options_from_last_find = nil
82 pager.replace(send(finder, *args) { |*a| yield(*a) if block_given? })
83
84 # magic counting for user convenience:
85 pager.total_entries = wp_count(count_options, args, finder) unless pager.total_entries
86 end
87 end
88
89 # Iterates through all records by loading one page at a time. This is useful
90 # for migrations or any other use case where you don't want to load all the
91 # records in memory at once.
92 #
93 # It uses +paginate+ internally; therefore it accepts all of its options.
94 # You can specify a starting page with <tt>:page</tt> (default is 1). Default
95 # <tt>:order</tt> is <tt>"id"</tt>, override if necessary.
96 #
97 # See {Faking Cursors in ActiveRecord}[http://weblog.jamisbuck.org/2007/4/6/faking-cursors-in-activerecord]
98 # where Jamis Buck describes this and a more efficient way for MySQL.
99 def paginated_each(options = {})
100 options = { :order => 'id', :page => 1 }.merge options
101 options[:page] = options[:page].to_i
102 options[:total_entries] = 0 # skip the individual count queries
103 total = 0
104
105 begin
106 collection = paginate(options)
107 with_exclusive_scope(:find => {}) do
108 # using exclusive scope so that the block is yielded in scope-free context
109 total += collection.each { |item| yield item }.size
110 end
111 options[:page] += 1
112 end until collection.size < collection.per_page
113
114 total
115 end
116
117 # Wraps +find_by_sql+ by simply adding LIMIT and OFFSET to your SQL string
118 # based on the params otherwise used by paginating finds: +page+ and
119 # +per_page+.
120 #
121 # Example:
122 #
123 # @developers = Developer.paginate_by_sql ['select * from developers where salary > ?', 80000],
124 # :page => params[:page], :per_page => 3
125 #
126 # A query for counting rows will automatically be generated if you don't
127 # supply <tt>:total_entries</tt>. If you experience problems with this
128 # generated SQL, you might want to perform the count manually in your
129 # application.
130 #
131 def paginate_by_sql(sql, options)
132 WillPaginate::Collection.create(*wp_parse_options(options)) do |pager|
133 query = sanitize_sql(sql.dup)
134 original_query = query.dup
135 # add limit, offset
136 add_limit! query, :offset => pager.offset, :limit => pager.per_page
137 # perfom the find
138 pager.replace find_by_sql(query)
139
140 unless pager.total_entries
141 count_query = original_query.sub /\bORDER\s+BY\s+[\w`,\s]+$/mi, ''
142 count_query = "SELECT COUNT(*) FROM (#{count_query})"
143
144 unless ['oracle', 'oci'].include?(self.connection.adapter_name.downcase)
145 count_query << ' AS count_table'
146 end
147 # perform the count query
148 pager.total_entries = count_by_sql(count_query)
149 end
150 end
151 end
152
153 def respond_to?(method, include_priv = false) #:nodoc:
154 case method.to_sym
155 when :paginate, :paginate_by_sql
156 true
157 else
158 super(method.to_s.sub(/^paginate/, 'find'), include_priv)
159 end
160 end
161
162 protected
163
164 def method_missing_with_paginate(method, *args) #:nodoc:
165 # did somebody tried to paginate? if not, let them be
166 unless method.to_s.index('paginate') == 0
167 if block_given?
168 return method_missing_without_paginate(method, *args) { |*a| yield(*a) }
169 else
170 return method_missing_without_paginate(method, *args)
171 end
172 end
173
174 # paginate finders are really just find_* with limit and offset
175 finder = method.to_s.sub('paginate', 'find')
176 finder.sub!('find', 'find_all') if finder.index('find_by_') == 0
177
178 options = args.pop
179 raise ArgumentError, 'parameter hash expected' unless options.respond_to? :symbolize_keys
180 options = options.dup
181 options[:finder] = finder
182 args << options
183
184 paginate(*args) { |*a| yield(*a) if block_given? }
185 end
186
187 # Does the not-so-trivial job of finding out the total number of entries
188 # in the database. It relies on the ActiveRecord +count+ method.
189 def wp_count(options, args, finder)
190 excludees = [:count, :order, :limit, :offset, :readonly]
191 excludees << :from unless ActiveRecord::Calculations::CALCULATIONS_OPTIONS.include?(:from)
192
193 # we may be in a model or an association proxy
194 klass = (@owner and @reflection) ? @reflection.klass : self
195
196 # Use :select from scope if it isn't already present.
197 options[:select] = scope(:find, :select) unless options[:select]
198
199 if options[:select] and options[:select] =~ /^\s*DISTINCT\b/i
200 # Remove quoting and check for table_name.*-like statement.
201 if options[:select].gsub('`', '') =~ /\w+\.\*/
202 options[:select] = "DISTINCT #{klass.table_name}.#{klass.primary_key}"
203 end
204 else
205 excludees << :select # only exclude the select param if it doesn't begin with DISTINCT
206 end
207
208 # count expects (almost) the same options as find
209 count_options = options.except *excludees
210
211 # merge the hash found in :count
212 # this allows you to specify :select, :order, or anything else just for the count query
213 count_options.update options[:count] if options[:count]
214
215 # forget about includes if they are irrelevant (Rails 2.1)
216 if count_options[:include] and
217 klass.private_methods.include?('references_eager_loaded_tables?') and
218 !klass.send(:references_eager_loaded_tables?, count_options)
219 count_options.delete :include
220 end
221
222 # we may have to scope ...
223 counter = Proc.new { count(count_options) }
224
225 count = if finder.index('find_') == 0 and klass.respond_to?(scoper = finder.sub('find', 'with'))
226 # scope_out adds a 'with_finder' method which acts like with_scope, if it's present
227 # then execute the count with the scoping provided by the with_finder
228 send(scoper, &counter)
229 elsif finder =~ /^find_(all_by|by)_([_a-zA-Z]\w*)$/
230 # extract conditions from calls like "paginate_by_foo_and_bar"
231 attribute_names = $2.split('_and_')
232 conditions = construct_attributes_from_arguments(attribute_names, args)
233 with_scope(:find => { :conditions => conditions }, &counter)
234 else
235 counter.call
236 end
237
238 count.respond_to?(:length) ? count.length : count
239 end
240
241 def wp_parse_options(options) #:nodoc:
242 raise ArgumentError, 'parameter hash expected' unless options.respond_to? :symbolize_keys
243 options = options.symbolize_keys
244 raise ArgumentError, ':page parameter required' unless options.key? :page
245
246 if options[:count] and options[:total_entries]
247 raise ArgumentError, ':count and :total_entries are mutually exclusive'
248 end
249
250 page = options[:page] || 1
251 per_page = options[:per_page] || self.per_page
252 total = options[:total_entries]
253 [page, per_page, total]
254 end
255
256 private
257
258 # def find_every_with_paginate(options)
259 # @options_from_last_find = options
260 # find_every_without_paginate(options)
261 # end
262 end
263 end
264end
diff --git a/vendor/plugins/will_paginate/lib/will_paginate/named_scope.rb b/vendor/plugins/will_paginate/lib/will_paginate/named_scope.rb
new file mode 100644
index 0000000..5a743d7
--- /dev/null
+++ b/vendor/plugins/will_paginate/lib/will_paginate/named_scope.rb
@@ -0,0 +1,170 @@
1module WillPaginate
2 # This is a feature backported from Rails 2.1 because of its usefullness not only with will_paginate,
3 # but in other aspects when managing complex conditions that you want to be reusable.
4 module NamedScope
5 # All subclasses of ActiveRecord::Base have two named_scopes:
6 # * <tt>all</tt>, which is similar to a <tt>find(:all)</tt> query, and
7 # * <tt>scoped</tt>, which allows for the creation of anonymous scopes, on the fly: <tt>Shirt.scoped(:conditions => {:color => 'red'}).scoped(:include => :washing_instructions)</tt>
8 #
9 # These anonymous scopes tend to be useful when procedurally generating complex queries, where passing
10 # intermediate values (scopes) around as first-class objects is convenient.
11 def self.included(base)
12 base.class_eval do
13 extend ClassMethods
14 named_scope :scoped, lambda { |scope| scope }
15 end
16 end
17
18 module ClassMethods
19 def scopes
20 read_inheritable_attribute(:scopes) || write_inheritable_attribute(:scopes, {})
21 end
22
23 # Adds a class method for retrieving and querying objects. A scope represents a narrowing of a database query,
24 # such as <tt>:conditions => {:color => :red}, :select => 'shirts.*', :include => :washing_instructions</tt>.
25 #
26 # class Shirt < ActiveRecord::Base
27 # named_scope :red, :conditions => {:color => 'red'}
28 # named_scope :dry_clean_only, :joins => :washing_instructions, :conditions => ['washing_instructions.dry_clean_only = ?', true]
29 # end
30 #
31 # The above calls to <tt>named_scope</tt> define class methods <tt>Shirt.red</tt> and <tt>Shirt.dry_clean_only</tt>. <tt>Shirt.red</tt>,
32 # in effect, represents the query <tt>Shirt.find(:all, :conditions => {:color => 'red'})</tt>.
33 #
34 # Unlike Shirt.find(...), however, the object returned by <tt>Shirt.red</tt> is not an Array; it resembles the association object
35 # constructed by a <tt>has_many</tt> declaration. For instance, you can invoke <tt>Shirt.red.find(:first)</tt>, <tt>Shirt.red.count</tt>,
36 # <tt>Shirt.red.find(:all, :conditions => {:size => 'small'})</tt>. Also, just
37 # as with the association objects, name scopes acts like an Array, implementing Enumerable; <tt>Shirt.red.each(&block)</tt>,
38 # <tt>Shirt.red.first</tt>, and <tt>Shirt.red.inject(memo, &block)</tt> all behave as if Shirt.red really were an Array.
39 #
40 # These named scopes are composable. For instance, <tt>Shirt.red.dry_clean_only</tt> will produce all shirts that are both red and dry clean only.
41 # Nested finds and calculations also work with these compositions: <tt>Shirt.red.dry_clean_only.count</tt> returns the number of garments
42 # for which these criteria obtain. Similarly with <tt>Shirt.red.dry_clean_only.average(:thread_count)</tt>.
43 #
44 # All scopes are available as class methods on the ActiveRecord::Base descendent upon which the scopes were defined. But they are also available to
45 # <tt>has_many</tt> associations. If,
46 #
47 # class Person < ActiveRecord::Base
48 # has_many :shirts
49 # end
50 #
51 # then <tt>elton.shirts.red.dry_clean_only</tt> will return all of Elton's red, dry clean
52 # only shirts.
53 #
54 # Named scopes can also be procedural.
55 #
56 # class Shirt < ActiveRecord::Base
57 # named_scope :colored, lambda { |color|
58 # { :conditions => { :color => color } }
59 # }
60 # end
61 #
62 # In this example, <tt>Shirt.colored('puce')</tt> finds all puce shirts.
63 #
64 # Named scopes can also have extensions, just as with <tt>has_many</tt> declarations:
65 #
66 # class Shirt < ActiveRecord::Base
67 # named_scope :red, :conditions => {:color => 'red'} do
68 # def dom_id
69 # 'red_shirts'
70 # end
71 # end
72 # end
73 #
74 #
75 # For testing complex named scopes, you can examine the scoping options using the
76 # <tt>proxy_options</tt> method on the proxy itself.
77 #
78 # class Shirt < ActiveRecord::Base
79 # named_scope :colored, lambda { |color|
80 # { :conditions => { :color => color } }
81 # }
82 # end
83 #
84 # expected_options = { :conditions => { :colored => 'red' } }
85 # assert_equal expected_options, Shirt.colored('red').proxy_options
86 def named_scope(name, options = {})
87 name = name.to_sym
88 scopes[name] = lambda do |parent_scope, *args|
89 Scope.new(parent_scope, case options
90 when Hash
91 options
92 when Proc
93 options.call(*args)
94 end) { |*a| yield(*a) if block_given? }
95 end
96 (class << self; self end).instance_eval do
97 define_method name do |*args|
98 scopes[name].call(self, *args)
99 end
100 end
101 end
102 end
103
104 class Scope
105 attr_reader :proxy_scope, :proxy_options
106
107 [].methods.each do |m|
108 unless m =~ /(^__|^nil\?|^send|^object_id$|class|extend|^find$|count|sum|average|maximum|minimum|paginate|first|last|empty\?|respond_to\?)/
109 delegate m, :to => :proxy_found
110 end
111 end
112
113 delegate :scopes, :with_scope, :to => :proxy_scope
114
115 def initialize(proxy_scope, options)
116 [options[:extend]].flatten.each { |extension| extend extension } if options[:extend]
117 extend Module.new { |*args| yield(*args) } if block_given?
118 @proxy_scope, @proxy_options = proxy_scope, options.except(:extend)
119 end
120
121 def reload
122 load_found; self
123 end
124
125 def first(*args)
126 if args.first.kind_of?(Integer) || (@found && !args.first.kind_of?(Hash))
127 proxy_found.first(*args)
128 else
129 find(:first, *args)
130 end
131 end
132
133 def last(*args)
134 if args.first.kind_of?(Integer) || (@found && !args.first.kind_of?(Hash))
135 proxy_found.last(*args)
136 else
137 find(:last, *args)
138 end
139 end
140
141 def empty?
142 @found ? @found.empty? : count.zero?
143 end
144
145 def respond_to?(method, include_private = false)
146 super || @proxy_scope.respond_to?(method, include_private)
147 end
148
149 protected
150 def proxy_found
151 @found || load_found
152 end
153
154 private
155 def method_missing(method, *args)
156 if scopes.include?(method)
157 scopes[method].call(self, *args)
158 else
159 with_scope :find => proxy_options do
160 proxy_scope.send(method, *args) { |*a| yield(*a) if block_given? }
161 end
162 end
163 end
164
165 def load_found
166 @found = find(:all)
167 end
168 end
169 end
170end
diff --git a/vendor/plugins/will_paginate/lib/will_paginate/named_scope_patch.rb b/vendor/plugins/will_paginate/lib/will_paginate/named_scope_patch.rb
new file mode 100644
index 0000000..7daff59
--- /dev/null
+++ b/vendor/plugins/will_paginate/lib/will_paginate/named_scope_patch.rb
@@ -0,0 +1,37 @@
1ActiveRecord::Associations::AssociationProxy.class_eval do
2 protected
3 def with_scope(*args)
4 @reflection.klass.send(:with_scope, *args) { |*a| yield(*a) if block_given? }
5 end
6end
7
8[ ActiveRecord::Associations::AssociationCollection,
9 ActiveRecord::Associations::HasManyThroughAssociation ].each do |klass|
10 klass.class_eval do
11 protected
12 alias :method_missing_without_scopes :method_missing_without_paginate
13 def method_missing_without_paginate(method, *args)
14 if @reflection.klass.scopes.include?(method)
15 @reflection.klass.scopes[method].call(self, *args) { |*a| yield(*a) if block_given? }
16 else
17 method_missing_without_scopes(method, *args) { |*a| yield(*a) if block_given? }
18 end
19 end
20 end
21end
22
23# Rails 1.2.6
24ActiveRecord::Associations::HasAndBelongsToManyAssociation.class_eval do
25 protected
26 def method_missing(method, *args)
27 if @target.respond_to?(method) || (!@reflection.klass.respond_to?(method) && Class.respond_to?(method))
28 super
29 elsif @reflection.klass.scopes.include?(method)
30 @reflection.klass.scopes[method].call(self, *args)
31 else
32 @reflection.klass.with_scope(:find => { :conditions => @finder_sql, :joins => @join_sql, :readonly => false }) do
33 @reflection.klass.send(method, *args) { |*a| yield(*a) if block_given? }
34 end
35 end
36 end
37end if ActiveRecord::Base.respond_to? :find_first
diff --git a/vendor/plugins/will_paginate/lib/will_paginate/version.rb b/vendor/plugins/will_paginate/lib/will_paginate/version.rb
new file mode 100644
index 0000000..99f3238
--- /dev/null
+++ b/vendor/plugins/will_paginate/lib/will_paginate/version.rb
@@ -0,0 +1,9 @@
1module WillPaginate
2 module VERSION
3 MAJOR = 2
4 MINOR = 3
5 TINY = 5
6
7 STRING = [MAJOR, MINOR, TINY].join('.')
8 end
9end
diff --git a/vendor/plugins/will_paginate/lib/will_paginate/view_helpers.rb b/vendor/plugins/will_paginate/lib/will_paginate/view_helpers.rb
new file mode 100644
index 0000000..5f7ae42
--- /dev/null
+++ b/vendor/plugins/will_paginate/lib/will_paginate/view_helpers.rb
@@ -0,0 +1,389 @@
1require 'will_paginate/core_ext'
2
3module WillPaginate
4 # = Will Paginate view helpers
5 #
6 # The main view helper, #will_paginate, renders
7 # pagination links for the given collection. The helper itself is lightweight
8 # and serves only as a wrapper around LinkRenderer instantiation; the
9 # renderer then does all the hard work of generating the HTML.
10 #
11 # == Global options for helpers
12 #
13 # Options for pagination helpers are optional and get their default values from the
14 # <tt>WillPaginate::ViewHelpers.pagination_options</tt> hash. You can write to this hash to
15 # override default options on the global level:
16 #
17 # WillPaginate::ViewHelpers.pagination_options[:previous_label] = 'Previous page'
18 #
19 # By putting this into "config/initializers/will_paginate.rb" (or simply environment.rb in
20 # older versions of Rails) you can easily translate link texts to previous
21 # and next pages, as well as override some other defaults to your liking.
22 module ViewHelpers
23 # default options that can be overridden on the global level
24 @@pagination_options = {
25 :class => 'pagination',
26 :previous_label => '&laquo; Previous',
27 :next_label => 'Next &raquo;',
28 :inner_window => 4, # links around the current page
29 :outer_window => 1, # links around beginning and end
30 :separator => ' ', # single space is friendly to spiders and non-graphic browsers
31 :param_name => :page,
32 :params => nil,
33 :renderer => 'WillPaginate::LinkRenderer',
34 :page_links => true,
35 :container => true
36 }
37 mattr_reader :pagination_options
38
39 # Renders Digg/Flickr-style pagination for a WillPaginate::Collection
40 # object. Nil is returned if there is only one page in total; no point in
41 # rendering the pagination in that case...
42 #
43 # ==== Options
44 # Display options:
45 # * <tt>:previous_label</tt> -- default: "« Previous" (this parameter is called <tt>:prev_label</tt> in versions <b>2.3.2</b> and older!)
46 # * <tt>:next_label</tt> -- default: "Next »"
47 # * <tt>:page_links</tt> -- when false, only previous/next links are rendered (default: true)
48 # * <tt>:inner_window</tt> -- how many links are shown around the current page (default: 4)
49 # * <tt>:outer_window</tt> -- how many links are around the first and the last page (default: 1)
50 # * <tt>:separator</tt> -- string separator for page HTML elements (default: single space)
51 #
52 # HTML options:
53 # * <tt>:class</tt> -- CSS class name for the generated DIV (default: "pagination")
54 # * <tt>:container</tt> -- toggles rendering of the DIV container for pagination links, set to
55 # false only when you are rendering your own pagination markup (default: true)
56 # * <tt>:id</tt> -- HTML ID for the container (default: nil). Pass +true+ to have the ID
57 # automatically generated from the class name of objects in collection: for example, paginating
58 # ArticleComment models would yield an ID of "article_comments_pagination".
59 #
60 # Advanced options:
61 # * <tt>:param_name</tt> -- parameter name for page number in URLs (default: <tt>:page</tt>)
62 # * <tt>:params</tt> -- additional parameters when generating pagination links
63 # (eg. <tt>:controller => "foo", :action => nil</tt>)
64 # * <tt>:renderer</tt> -- class name, class or instance of a link renderer (default:
65 # <tt>WillPaginate::LinkRenderer</tt>)
66 #
67 # All options not recognized by will_paginate will become HTML attributes on the container
68 # element for pagination links (the DIV). For example:
69 #
70 # <%= will_paginate @posts, :style => 'font-size: small' %>
71 #
72 # ... will result in:
73 #
74 # <div class="pagination" style="font-size: small"> ... </div>
75 #
76 # ==== Using the helper without arguments
77 # If the helper is called without passing in the collection object, it will
78 # try to read from the instance variable inferred by the controller name.
79 # For example, calling +will_paginate+ while the current controller is
80 # PostsController will result in trying to read from the <tt>@posts</tt>
81 # variable. Example:
82 #
83 # <%= will_paginate :id => true %>
84 #
85 # ... will result in <tt>@post</tt> collection getting paginated:
86 #
87 # <div class="pagination" id="posts_pagination"> ... </div>
88 #
89 def will_paginate(collection = nil, options = {})
90 options, collection = collection, nil if collection.is_a? Hash
91 unless collection or !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?" unless collection
96 end
97 # early exit if there is nothing to render
98 return nil unless WillPaginate::ViewHelpers.total_pages_for_collection(collection) > 1
99
100 options = options.symbolize_keys.reverse_merge WillPaginate::ViewHelpers.pagination_options
101 if options[:prev_label]
102 WillPaginate::Deprecation::warn(":prev_label view parameter is now :previous_label; the old name has been deprecated", caller)
103 options[:previous_label] = options.delete(:prev_label)
104 end
105
106 # get the renderer instance
107 renderer = case options[:renderer]
108 when String
109 options[:renderer].to_s.constantize.new
110 when Class
111 options[:renderer].new
112 else
113 options[:renderer]
114 end
115 # render HTML for pagination
116 renderer.prepare collection, options, self
117 renderer.to_html
118 end
119
120 # Wrapper for rendering pagination links at both top and bottom of a block
121 # of content.
122 #
123 # <% paginated_section @posts do %>
124 # <ol id="posts">
125 # <% for post in @posts %>
126 # <li> ... </li>
127 # <% end %>
128 # </ol>
129 # <% end %>
130 #
131 # will result in:
132 #
133 # <div class="pagination"> ... </div>
134 # <ol id="posts">
135 # ...
136 # </ol>
137 # <div class="pagination"> ... </div>
138 #
139 # Arguments are passed to a <tt>will_paginate</tt> call, so the same options
140 # apply. Don't use the <tt>:id</tt> option; otherwise you'll finish with two
141 # blocks of pagination links sharing the same ID (which is invalid HTML).
142 def paginated_section(*args, &block)
143 pagination = will_paginate(*args).to_s
144
145 unless ActionView::Base.respond_to? :erb_variable
146 concat pagination
147 yield
148 concat pagination
149 else
150 content = pagination + capture(&block) + pagination
151 concat(content, block.binding)
152 end
153 end
154
155 # Renders a helpful message with numbers of displayed vs. total entries.
156 # You can use this as a blueprint for your own, similar helpers.
157 #
158 # <%= page_entries_info @posts %>
159 # #-> Displaying posts 6 - 10 of 26 in total
160 #
161 # By default, the message will use the humanized class name of objects
162 # in collection: for instance, "project types" for ProjectType models.
163 # Override this with the <tt>:entry_name</tt> parameter:
164 #
165 # <%= page_entries_info @posts, :entry_name => 'item' %>
166 # #-> Displaying items 6 - 10 of 26 in total
167 def page_entries_info(collection, options = {})
168 entry_name = options[:entry_name] ||
169 (collection.empty?? 'entry' : collection.first.class.name.underscore.sub('_', ' '))
170
171 if collection.total_pages < 2
172 case collection.size
173 when 0; "No #{entry_name.pluralize} found"
174 when 1; "Displaying <b>1</b> #{entry_name}"
175 else; "Displaying <b>all #{collection.size}</b> #{entry_name.pluralize}"
176 end
177 else
178 %{Displaying #{entry_name.pluralize} <b>%d&nbsp;-&nbsp;%d</b> of <b>%d</b> in total} % [
179 collection.offset + 1,
180 collection.offset + collection.length,
181 collection.total_entries
182 ]
183 end
184 end
185
186 def self.total_pages_for_collection(collection) #:nodoc:
187 if collection.respond_to?('page_count') and !collection.respond_to?('total_pages')
188 WillPaginate::Deprecation.warn %{
189 You are using a paginated collection of class #{collection.class.name}
190 which conforms to the old API of WillPaginate::Collection by using
191 `page_count`, while the current method name is `total_pages`. Please
192 upgrade yours or 3rd-party code that provides the paginated collection}, caller
193 class << collection
194 def total_pages; page_count; end
195 end
196 end
197 collection.total_pages
198 end
199 end
200
201 # This class does the heavy lifting of actually building the pagination
202 # links. It is used by the <tt>will_paginate</tt> helper internally.
203 class LinkRenderer
204
205 # The gap in page links is represented by:
206 #
207 # <span class="gap">&hellip;</span>
208 attr_accessor :gap_marker
209
210 def initialize
211 @gap_marker = '<span class="gap">&hellip;</span>'
212 end
213
214 # * +collection+ is a WillPaginate::Collection instance or any other object
215 # that conforms to that API
216 # * +options+ are forwarded from +will_paginate+ view helper
217 # * +template+ is the reference to the template being rendered
218 def prepare(collection, options, template)
219 @collection = collection
220 @options = options
221 @template = template
222
223 # reset values in case we're re-using this instance
224 @total_pages = @param_name = @url_string = nil
225 end
226
227 # Process it! This method returns the complete HTML string which contains
228 # pagination links. Feel free to subclass LinkRenderer and change this
229 # method as you see fit.
230 def to_html
231 links = @options[:page_links] ? windowed_links : []
232 # previous/next buttons
233 links.unshift page_link_or_span(@collection.previous_page, 'disabled prev_page', @options[:previous_label])
234 links.push page_link_or_span(@collection.next_page, 'disabled next_page', @options[:next_label])
235
236 html = links.join(@options[:separator])
237 @options[:container] ? @template.content_tag(:div, html, html_attributes) : html
238 end
239
240 # Returns the subset of +options+ this instance was initialized with that
241 # represent HTML attributes for the container element of pagination links.
242 def html_attributes
243 return @html_attributes if @html_attributes
244 @html_attributes = @options.except *(WillPaginate::ViewHelpers.pagination_options.keys - [:class])
245 # pagination of Post models will have the ID of "posts_pagination"
246 if @options[:container] and @options[:id] === true
247 @html_attributes[:id] = @collection.first.class.name.underscore.pluralize + '_pagination'
248 end
249 @html_attributes
250 end
251
252 protected
253
254 # Collects link items for visible page numbers.
255 def windowed_links
256 prev = nil
257
258 visible_page_numbers.inject [] do |links, n|
259 # detect gaps:
260 links << gap_marker if prev and n > prev + 1
261 links << page_link_or_span(n, 'current')
262 prev = n
263 links
264 end
265 end
266
267 # Calculates visible page numbers using the <tt>:inner_window</tt> and
268 # <tt>:outer_window</tt> options.
269 def visible_page_numbers
270 inner_window, outer_window = @options[:inner_window].to_i, @options[:outer_window].to_i
271 window_from = current_page - inner_window
272 window_to = current_page + inner_window
273
274 # adjust lower or upper limit if other is out of bounds
275 if window_to > total_pages
276 window_from -= window_to - total_pages
277 window_to = total_pages
278 end
279 if window_from < 1
280 window_to += 1 - window_from
281 window_from = 1
282 window_to = total_pages if window_to > total_pages
283 end
284
285 visible = (1..total_pages).to_a
286 left_gap = (2 + outer_window)...window_from
287 right_gap = (window_to + 1)...(total_pages - outer_window)
288 visible -= left_gap.to_a if left_gap.last - left_gap.first > 1
289 visible -= right_gap.to_a if right_gap.last - right_gap.first > 1
290
291 visible
292 end
293
294 def page_link_or_span(page, span_class, text = nil)
295 text ||= page.to_s
296
297 if page and page != current_page
298 classnames = span_class && span_class.index(' ') && span_class.split(' ', 2).last
299 page_link page, text, :rel => rel_value(page), :class => classnames
300 else
301 page_span page, text, :class => span_class
302 end
303 end
304
305 def page_link(page, text, attributes = {})
306 @template.link_to text, url_for(page), attributes
307 end
308
309 def page_span(page, text, attributes = {})
310 @template.content_tag :span, text, attributes
311 end
312
313 # Returns URL params for +page_link_or_span+, taking the current GET params
314 # and <tt>:params</tt> option into account.
315 def url_for(page)
316 page_one = page == 1
317 unless @url_string and !page_one
318 @url_params = {}
319 # page links should preserve GET parameters
320 stringified_merge @url_params, @template.params if @template.request.get?
321 stringified_merge @url_params, @options[:params] if @options[:params]
322
323 if complex = param_name.index(/[^\w-]/)
324 page_param = (defined?(CGIMethods) ? CGIMethods : ActionController::AbstractRequest).
325 parse_query_parameters("#{param_name}=#{page}")
326
327 stringified_merge @url_params, page_param
328 else
329 @url_params[param_name] = page_one ? 1 : 2
330 end
331
332 url = @template.url_for(@url_params)
333 return url if page_one
334
335 if complex
336 @url_string = url.sub(%r!((?:\?|&amp;)#{CGI.escape param_name}=)#{page}!, '\1@')
337 return url
338 else
339 @url_string = url
340 @url_params[param_name] = 3
341 @template.url_for(@url_params).split(//).each_with_index do |char, i|
342 if char == '3' and url[i, 1] == '2'
343 @url_string[i] = '@'
344 break
345 end
346 end
347 end
348 end
349 # finally!
350 @url_string.sub '@', page.to_s
351 end
352
353 private
354
355 def rel_value(page)
356 case page
357 when @collection.previous_page; 'prev' + (page == 1 ? ' start' : '')
358 when @collection.next_page; 'next'
359 when 1; 'start'
360 end
361 end
362
363 def current_page
364 @collection.current_page
365 end
366
367 def total_pages
368 @total_pages ||= WillPaginate::ViewHelpers.total_pages_for_collection(@collection)
369 end
370
371 def param_name
372 @param_name ||= @options[:param_name].to_s
373 end
374
375 # Recursively merge into target hash by using stringified keys from the other one
376 def stringified_merge(target, other)
377 other.each do |key, value|
378 key = key.to_s # this line is what it's all about!
379 existing = target[key]
380
381 if value.is_a?(Hash) and (existing.is_a?(Hash) or existing.nil?)
382 stringified_merge(existing || (target[key] = {}), value)
383 else
384 target[key] = value
385 end
386 end
387 end
388 end
389end
diff --git a/vendor/plugins/will_paginate/test/boot.rb b/vendor/plugins/will_paginate/test/boot.rb
new file mode 100644
index 0000000..622fc93
--- /dev/null
+++ b/vendor/plugins/will_paginate/test/boot.rb
@@ -0,0 +1,21 @@
1plugin_root = File.join(File.dirname(__FILE__), '..')
2version = ENV['RAILS_VERSION']
3version = nil if version and version == ""
4
5# first look for a symlink to a copy of the framework
6if !version and framework_root = ["#{plugin_root}/rails", "#{plugin_root}/../../rails"].find { |p| File.directory? p }
7 puts "found framework root: #{framework_root}"
8 # this allows for a plugin to be tested outside of an app and without Rails gems
9 $:.unshift "#{framework_root}/activesupport/lib", "#{framework_root}/activerecord/lib", "#{framework_root}/actionpack/lib"
10else
11 # simply use installed gems if available
12 puts "using Rails#{version ? ' ' + version : nil} gems"
13 require 'rubygems'
14
15 if version
16 gem 'rails', version
17 else
18 gem 'actionpack'
19 gem 'activerecord'
20 end
21end
diff --git a/vendor/plugins/will_paginate/test/collection_test.rb b/vendor/plugins/will_paginate/test/collection_test.rb
new file mode 100644
index 0000000..a9336bb
--- /dev/null
+++ b/vendor/plugins/will_paginate/test/collection_test.rb
@@ -0,0 +1,143 @@
1require 'helper'
2require 'will_paginate/array'
3
4class ArrayPaginationTest < Test::Unit::TestCase
5
6 def setup ; end
7
8 def test_simple
9 collection = ('a'..'e').to_a
10
11 [{ :page => 1, :per_page => 3, :expected => %w( a b c ) },
12 { :page => 2, :per_page => 3, :expected => %w( d e ) },
13 { :page => 1, :per_page => 5, :expected => %w( a b c d e ) },
14 { :page => 3, :per_page => 5, :expected => [] },
15 ].
16 each do |conditions|
17 expected = conditions.delete :expected
18 assert_equal expected, collection.paginate(conditions)
19 end
20 end
21
22 def test_defaults
23 result = (1..50).to_a.paginate
24 assert_equal 1, result.current_page
25 assert_equal 30, result.size
26 end
27
28 def test_deprecated_api
29 assert_raise(ArgumentError) { [].paginate(2) }
30 assert_raise(ArgumentError) { [].paginate(2, 10) }
31 end
32
33 def test_total_entries_has_precedence
34 result = %w(a b c).paginate :total_entries => 5
35 assert_equal 5, result.total_entries
36 end
37
38 def test_argument_error_with_params_and_another_argument
39 assert_raise ArgumentError do
40 [].paginate({}, 5)
41 end
42 end
43
44 def test_paginated_collection
45 entries = %w(a b c)
46 collection = create(2, 3, 10) do |pager|
47 assert_equal entries, pager.replace(entries)
48 end
49
50 assert_equal entries, collection
51 assert_respond_to_all collection, %w(total_pages each offset size current_page per_page total_entries)
52 assert_kind_of Array, collection
53 assert_instance_of Array, collection.entries
54 assert_equal 3, collection.offset
55 assert_equal 4, collection.total_pages
56 assert !collection.out_of_bounds?
57 end
58
59 def test_previous_next_pages
60 collection = create(1, 1, 3)
61 assert_nil collection.previous_page
62 assert_equal 2, collection.next_page
63
64 collection = create(2, 1, 3)
65 assert_equal 1, collection.previous_page
66 assert_equal 3, collection.next_page
67
68 collection = create(3, 1, 3)
69 assert_equal 2, collection.previous_page
70 assert_nil collection.next_page
71 end
72
73 def test_out_of_bounds
74 entries = create(2, 3, 2){}
75 assert entries.out_of_bounds?
76
77 entries = create(1, 3, 2){}
78 assert !entries.out_of_bounds?
79 end
80
81 def test_guessing_total_count
82 entries = create do |pager|
83 # collection is shorter than limit
84 pager.replace array
85 end
86 assert_equal 8, entries.total_entries
87
88 entries = create(2, 5, 10) do |pager|
89 # collection is shorter than limit, but we have an explicit count
90 pager.replace array
91 end
92 assert_equal 10, entries.total_entries
93
94 entries = create do |pager|
95 # collection is the same as limit; we can't guess
96 pager.replace array(5)
97 end
98 assert_equal nil, entries.total_entries
99
100 entries = create do |pager|
101 # collection is empty; we can't guess
102 pager.replace array(0)
103 end
104 assert_equal nil, entries.total_entries
105
106 entries = create(1) do |pager|
107 # collection is empty and we're on page 1,
108 # so the whole thing must be empty, too
109 pager.replace array(0)
110 end
111 assert_equal 0, entries.total_entries
112 end
113
114 def test_invalid_page
115 bad_inputs = [0, -1, nil, '', 'Schnitzel']
116
117 bad_inputs.each do |bad|
118 assert_raise(WillPaginate::InvalidPage) { create bad }
119 end
120 end
121
122 def test_invalid_per_page_setting
123 assert_raise(ArgumentError) { create(1, -1) }
124 end
125
126 def test_page_count_was_removed
127 assert_raise(NoMethodError) { create.page_count }
128 # It's `total_pages` now.
129 end
130
131 private
132 def create(page = 2, limit = 5, total = nil, &block)
133 if block_given?
134 WillPaginate::Collection.create(page, limit, total, &block)
135 else
136 WillPaginate::Collection.new(page, limit, total)
137 end
138 end
139
140 def array(size = 3)
141 Array.new(size)
142 end
143end
diff --git a/vendor/plugins/will_paginate/test/console b/vendor/plugins/will_paginate/test/console
new file mode 100755
index 0000000..3f282f1
--- /dev/null
+++ b/vendor/plugins/will_paginate/test/console
@@ -0,0 +1,8 @@
1#!/usr/bin/env ruby
2irb = RUBY_PLATFORM =~ /(:?mswin|mingw)/ ? 'irb.bat' : 'irb'
3libs = []
4
5libs << 'irb/completion'
6libs << File.join('lib', 'load_fixtures')
7
8exec "#{irb} -Ilib:test#{libs.map{ |l| " -r #{l}" }.join} --simple-prompt"
diff --git a/vendor/plugins/will_paginate/test/finder_test.rb b/vendor/plugins/will_paginate/test/finder_test.rb
new file mode 100644
index 0000000..38ef565
--- /dev/null
+++ b/vendor/plugins/will_paginate/test/finder_test.rb
@@ -0,0 +1,476 @@
1require 'helper'
2require 'lib/activerecord_test_case'
3
4require 'will_paginate'
5WillPaginate.enable_activerecord
6WillPaginate.enable_named_scope
7
8class FinderTest < ActiveRecordTestCase
9 fixtures :topics, :replies, :users, :projects, :developers_projects
10
11 def test_new_methods_presence
12 assert_respond_to_all Topic, %w(per_page paginate paginate_by_sql)
13 end
14
15 def test_simple_paginate
16 assert_queries(1) do
17 entries = Topic.paginate :page => nil
18 assert_equal 1, entries.current_page
19 assert_equal 1, entries.total_pages
20 assert_equal 4, entries.size
21 end
22
23 assert_queries(2) do
24 entries = Topic.paginate :page => 2
25 assert_equal 1, entries.total_pages
26 assert entries.empty?
27 end
28 end
29
30 def test_parameter_api
31 # :page parameter in options is required!
32 assert_raise(ArgumentError){ Topic.paginate }
33 assert_raise(ArgumentError){ Topic.paginate({}) }
34
35 # explicit :all should not break anything
36 assert_equal Topic.paginate(:page => nil), Topic.paginate(:all, :page => 1)
37
38 # :count could be nil and we should still not cry
39 assert_nothing_raised { Topic.paginate :page => 1, :count => nil }
40 end
41
42 def test_paginate_with_per_page
43 entries = Topic.paginate :page => 1, :per_page => 1
44 assert_equal 1, entries.size
45 assert_equal 4, entries.total_pages
46
47 # Developer class has explicit per_page at 10
48 entries = Developer.paginate :page => 1
49 assert_equal 10, entries.size
50 assert_equal 2, entries.total_pages
51
52 entries = Developer.paginate :page => 1, :per_page => 5
53 assert_equal 11, entries.total_entries
54 assert_equal 5, entries.size
55 assert_equal 3, entries.total_pages
56 end
57
58 def test_paginate_with_order
59 entries = Topic.paginate :page => 1, :order => 'created_at desc'
60 expected = [topics(:futurama), topics(:harvey_birdman), topics(:rails), topics(:ar)].reverse
61 assert_equal expected, entries.to_a
62 assert_equal 1, entries.total_pages
63 end
64
65 def test_paginate_with_conditions
66 entries = Topic.paginate :page => 1, :conditions => ["created_at > ?", 30.minutes.ago]
67 expected = [topics(:rails), topics(:ar)]
68 assert_equal expected, entries.to_a
69 assert_equal 1, entries.total_pages
70 end
71
72 def test_paginate_with_include_and_conditions
73 entries = Topic.paginate \
74 :page => 1,
75 :include => :replies,
76 :conditions => "replies.content LIKE 'Bird%' ",
77 :per_page => 10
78
79 expected = Topic.find :all,
80 :include => 'replies',
81 :conditions => "replies.content LIKE 'Bird%' ",
82 :limit => 10
83
84 assert_equal expected, entries.to_a
85 assert_equal 1, entries.total_entries
86 end
87
88 def test_paginate_with_include_and_order
89 entries = nil
90 assert_queries(2) do
91 entries = Topic.paginate \
92 :page => 1,
93 :include => :replies,
94 :order => 'replies.created_at asc, topics.created_at asc',
95 :per_page => 10
96 end
97
98 expected = Topic.find :all,
99 :include => 'replies',
100 :order => 'replies.created_at asc, topics.created_at asc',
101 :limit => 10
102
103 assert_equal expected, entries.to_a
104 assert_equal 4, entries.total_entries
105 end
106
107 def test_paginate_associations_with_include
108 entries, project = nil, projects(:active_record)
109
110 assert_nothing_raised "THIS IS A BUG in Rails 1.2.3 that was fixed in [7326]. " +
111 "Please upgrade to a newer version of Rails." do
112 entries = project.topics.paginate \
113 :page => 1,
114 :include => :replies,
115 :conditions => "replies.content LIKE 'Nice%' ",
116 :per_page => 10
117 end
118
119 expected = Topic.find :all,
120 :include => 'replies',
121 :conditions => "project_id = #{project.id} AND replies.content LIKE 'Nice%' ",
122 :limit => 10
123
124 assert_equal expected, entries.to_a
125 end
126
127 def test_paginate_associations
128 dhh = users :david
129 expected_name_ordered = [projects(:action_controller), projects(:active_record)]
130 expected_id_ordered = [projects(:active_record), projects(:action_controller)]
131
132 assert_queries(2) do
133 # with association-specified order
134 entries = dhh.projects.paginate(:page => 1)
135 assert_equal expected_name_ordered, entries
136 assert_equal 2, entries.total_entries
137 end
138
139 # with explicit order
140 entries = dhh.projects.paginate(:page => 1, :order => 'projects.id')
141 assert_equal expected_id_ordered, entries
142 assert_equal 2, entries.total_entries
143
144 assert_nothing_raised { dhh.projects.find(:all, :order => 'projects.id', :limit => 4) }
145 entries = dhh.projects.paginate(:page => 1, :order => 'projects.id', :per_page => 4)
146 assert_equal expected_id_ordered, entries
147
148 # has_many with implicit order
149 topic = Topic.find(1)
150 expected = [replies(:spam), replies(:witty_retort)]
151 assert_equal expected.map(&:id).sort, topic.replies.paginate(:page => 1).map(&:id).sort
152 assert_equal expected.reverse, topic.replies.paginate(:page => 1, :order => 'replies.id ASC')
153 end
154
155 def test_paginate_association_extension
156 project = Project.find(:first)
157
158 assert_queries(2) do
159 entries = project.replies.paginate_recent :page => 1
160 assert_equal [replies(:brave)], entries
161 end
162 end
163
164 def test_paginate_with_joins
165 entries = nil
166
167 assert_queries(1) do
168 entries = Developer.paginate :page => 1,
169 :joins => 'LEFT JOIN developers_projects ON users.id = developers_projects.developer_id',
170 :conditions => 'project_id = 1'
171 assert_equal 2, entries.size
172 developer_names = entries.map &:name
173 assert developer_names.include?('David')
174 assert developer_names.include?('Jamis')
175 end
176
177 assert_queries(1) do
178 expected = entries.to_a
179 entries = Developer.paginate :page => 1,
180 :joins => 'LEFT JOIN developers_projects ON users.id = developers_projects.developer_id',
181 :conditions => 'project_id = 1', :count => { :select => "users.id" }
182 assert_equal expected, entries.to_a
183 assert_equal 2, entries.total_entries
184 end
185 end
186
187 def test_paginate_with_group
188 entries = nil
189 assert_queries(1) do
190 entries = Developer.paginate :page => 1, :per_page => 10,
191 :group => 'salary', :select => 'salary', :order => 'salary'
192 end
193
194 expected = [ users(:david), users(:jamis), users(:dev_10), users(:poor_jamis) ].map(&:salary).sort
195 assert_equal expected, entries.map(&:salary)
196 end
197
198 def test_paginate_with_dynamic_finder
199 expected = [replies(:witty_retort), replies(:spam)]
200 assert_equal expected, Reply.paginate_by_topic_id(1, :page => 1)
201
202 entries = Developer.paginate :conditions => { :salary => 100000 }, :page => 1, :per_page => 5
203 assert_equal 8, entries.total_entries
204 assert_equal entries, Developer.paginate_by_salary(100000, :page => 1, :per_page => 5)
205
206 # dynamic finder + conditions
207 entries = Developer.paginate_by_salary(100000, :page => 1,
208 :conditions => ['id > ?', 6])
209 assert_equal 4, entries.total_entries
210 assert_equal (7..10).to_a, entries.map(&:id)
211
212 assert_raises NoMethodError do
213 Developer.paginate_by_inexistent_attribute 100000, :page => 1
214 end
215 end
216
217 def test_scoped_paginate
218 entries = Developer.with_poor_ones { Developer.paginate :page => 1 }
219
220 assert_equal 2, entries.size
221 assert_equal 2, entries.total_entries
222 end
223
224 ## named_scope ##
225
226 def test_paginate_in_named_scope
227 entries = Developer.poor.paginate :page => 1, :per_page => 1
228
229 assert_equal 1, entries.size
230 assert_equal 2, entries.total_entries
231 end
232
233 def test_paginate_in_named_scope_on_habtm_association
234 project = projects(:active_record)
235 assert_queries(2) do
236 entries = project.developers.poor.paginate :page => 1, :per_page => 1
237
238 assert_equal 1, entries.size, 'one developer should be found'
239 assert_equal 1, entries.total_entries, 'only one developer should be found'
240 end
241 end
242
243 def test_paginate_in_named_scope_on_hmt_association
244 project = projects(:active_record)
245 expected = [replies(:brave)]
246
247 assert_queries(2) do
248 entries = project.replies.recent.paginate :page => 1, :per_page => 1
249 assert_equal expected, entries
250 assert_equal 1, entries.total_entries, 'only one reply should be found'
251 end
252 end
253
254 def test_paginate_in_named_scope_on_has_many_association
255 project = projects(:active_record)
256 expected = [topics(:ar)]
257
258 assert_queries(2) do
259 entries = project.topics.mentions_activerecord.paginate :page => 1, :per_page => 1
260 assert_equal expected, entries
261 assert_equal 1, entries.total_entries, 'only one topic should be found'
262 end
263 end
264
265 def test_named_scope_with_include
266 project = projects(:active_record)
267 entries = project.topics.with_replies_starting_with('AR ').paginate(:page => 1, :per_page => 1)
268 assert_equal 1, entries.size
269 end
270
271 ## misc ##
272
273 def test_count_and_total_entries_options_are_mutually_exclusive
274 e = assert_raise ArgumentError do
275 Developer.paginate :page => 1, :count => {}, :total_entries => 1
276 end
277 assert_match /exclusive/, e.to_s
278 end
279
280 def test_readonly
281 assert_nothing_raised { Developer.paginate :readonly => true, :page => 1 }
282 end
283
284 # this functionality is temporarily removed
285 def xtest_pagination_defines_method
286 pager = "paginate_by_created_at"
287 assert !User.methods.include?(pager), "User methods should not include `#{pager}` method"
288 # paginate!
289 assert 0, User.send(pager, nil, :page => 1).total_entries
290 # the paging finder should now be defined
291 assert User.methods.include?(pager), "`#{pager}` method should be defined on User"
292 end
293
294 # Is this Rails 2.0? Find out by testing find_all which was removed in [6998]
295 unless ActiveRecord::Base.respond_to? :find_all
296 def test_paginate_array_of_ids
297 # AR finders also accept arrays of IDs
298 # (this was broken in Rails before [6912])
299 assert_queries(1) do
300 entries = Developer.paginate((1..8).to_a, :per_page => 3, :page => 2, :order => 'id')
301 assert_equal (4..6).to_a, entries.map(&:id)
302 assert_equal 8, entries.total_entries
303 end
304 end
305 end
306
307 uses_mocha 'internals' do
308 def test_implicit_all_with_dynamic_finders
309 Topic.expects(:find_all_by_foo).returns([])
310 Topic.expects(:count).returns(0)
311 Topic.paginate_by_foo :page => 2
312 end
313
314 def test_guessing_the_total_count
315 Topic.expects(:find).returns(Array.new(2))
316 Topic.expects(:count).never
317
318 entries = Topic.paginate :page => 2, :per_page => 4
319 assert_equal 6, entries.total_entries
320 end
321
322 def test_guessing_that_there_are_no_records
323 Topic.expects(:find).returns([])
324 Topic.expects(:count).never
325
326 entries = Topic.paginate :page => 1, :per_page => 4
327 assert_equal 0, entries.total_entries
328 end
329
330 def test_extra_parameters_stay_untouched
331 Topic.expects(:find).with(:all, {:foo => 'bar', :limit => 4, :offset => 0 }).returns(Array.new(5))
332 Topic.expects(:count).with({:foo => 'bar'}).returns(1)
333
334 Topic.paginate :foo => 'bar', :page => 1, :per_page => 4
335 end
336
337 def test_count_skips_select
338 Developer.stubs(:find).returns([])
339 Developer.expects(:count).with({}).returns(0)
340 Developer.paginate :select => 'salary', :page => 2
341 end
342
343 def test_count_select_when_distinct
344 Developer.stubs(:find).returns([])
345 Developer.expects(:count).with(:select => 'DISTINCT salary').returns(0)
346 Developer.paginate :select => 'DISTINCT salary', :page => 2
347 end
348
349 def test_count_with_scoped_select_when_distinct
350 Developer.stubs(:find).returns([])
351 Developer.expects(:count).with(:select => 'DISTINCT users.id').returns(0)
352 Developer.distinct.paginate :page => 2
353 end
354
355 def test_should_use_scoped_finders_if_present
356 # scope-out compatibility
357 Topic.expects(:find_best).returns(Array.new(5))
358 Topic.expects(:with_best).returns(1)
359
360 Topic.paginate_best :page => 1, :per_page => 4
361 end
362
363 def test_paginate_by_sql
364 assert_respond_to Developer, :paginate_by_sql
365 Developer.expects(:find_by_sql).with(regexp_matches(/sql LIMIT 3(,| OFFSET) 3/)).returns([])
366 Developer.expects(:count_by_sql).with('SELECT COUNT(*) FROM (sql) AS count_table').returns(0)
367
368 entries = Developer.paginate_by_sql 'sql', :page => 2, :per_page => 3
369 end
370
371 def test_paginate_by_sql_respects_total_entries_setting
372 Developer.expects(:find_by_sql).returns([])
373 Developer.expects(:count_by_sql).never
374
375 entries = Developer.paginate_by_sql 'sql', :page => 1, :total_entries => 999
376 assert_equal 999, entries.total_entries
377 end
378
379 def test_paginate_by_sql_strips_order_by_when_counting
380 Developer.expects(:find_by_sql).returns([])
381 Developer.expects(:count_by_sql).with("SELECT COUNT(*) FROM (sql\n ) AS count_table").returns(0)
382
383 Developer.paginate_by_sql "sql\n ORDER\nby foo, bar, `baz` ASC", :page => 2
384 end
385
386 # TODO: counts are still wrong
387 def test_ability_to_use_with_custom_finders
388 # acts_as_taggable defines find_tagged_with(tag, options)
389 Topic.expects(:find_tagged_with).with('will_paginate', :offset => 5, :limit => 5).returns([])
390 Topic.expects(:count).with({}).returns(0)
391
392 Topic.paginate_tagged_with 'will_paginate', :page => 2, :per_page => 5
393 end
394
395 def test_array_argument_doesnt_eliminate_count
396 ids = (1..8).to_a
397 Developer.expects(:find_all_by_id).returns([])
398 Developer.expects(:count).returns(0)
399
400 Developer.paginate_by_id(ids, :per_page => 3, :page => 2, :order => 'id')
401 end
402
403 def test_paginating_finder_doesnt_mangle_options
404 Developer.expects(:find).returns([])
405 options = { :page => 1, :per_page => 2, :foo => 'bar' }
406 options_before = options.dup
407
408 Developer.paginate(options)
409 assert_equal options_before, options
410 end
411
412 def test_paginate_by_sql_doesnt_change_original_query
413 query = 'SQL QUERY'
414 original_query = query.dup
415 Developer.expects(:find_by_sql).returns([])
416
417 Developer.paginate_by_sql query, :page => 1
418 assert_equal original_query, query
419 end
420
421 def test_paginated_each
422 collection = stub('collection', :size => 5, :empty? => false, :per_page => 5)
423 collection.expects(:each).times(2).returns(collection)
424 last_collection = stub('collection', :size => 4, :empty? => false, :per_page => 5)
425 last_collection.expects(:each).returns(last_collection)
426
427 params = { :order => 'id', :total_entries => 0 }
428
429 Developer.expects(:paginate).with(params.merge(:page => 2)).returns(collection)
430 Developer.expects(:paginate).with(params.merge(:page => 3)).returns(collection)
431 Developer.expects(:paginate).with(params.merge(:page => 4)).returns(last_collection)
432
433 assert_equal 14, Developer.paginated_each(:page => '2') { }
434 end
435
436 def test_paginated_each_with_named_scope
437 assert_equal 2, Developer.poor.paginated_each(:per_page => 1) {
438 assert_equal 11, Developer.count
439 }
440 end
441
442 # detect ActiveRecord 2.1
443 if ActiveRecord::Base.private_methods.include?('references_eager_loaded_tables?')
444 def test_removes_irrelevant_includes_in_count
445 Developer.expects(:find).returns([1])
446 Developer.expects(:count).with({}).returns(0)
447
448 Developer.paginate :page => 1, :per_page => 1, :include => :projects
449 end
450
451 def test_doesnt_remove_referenced_includes_in_count
452 Developer.expects(:find).returns([1])
453 Developer.expects(:count).with({ :include => :projects, :conditions => 'projects.id > 2' }).returns(0)
454
455 Developer.paginate :page => 1, :per_page => 1,
456 :include => :projects, :conditions => 'projects.id > 2'
457 end
458 end
459
460 def test_paginate_from
461 result = Developer.paginate(:from => 'users', :page => 1, :per_page => 1)
462 assert_equal 1, result.size
463 end
464
465 def test_hmt_with_include
466 # ticket #220
467 reply = projects(:active_record).replies.find(:first, :order => 'replies.id')
468 assert_equal replies(:decisive), reply
469
470 # ticket #223
471 Project.find(1, :include => :replies)
472
473 # I cannot reproduce any of the failures from those reports :(
474 end
475 end
476end
diff --git a/vendor/plugins/will_paginate/test/fixtures/admin.rb b/vendor/plugins/will_paginate/test/fixtures/admin.rb
new file mode 100644
index 0000000..1d5e7f3
--- /dev/null
+++ b/vendor/plugins/will_paginate/test/fixtures/admin.rb
@@ -0,0 +1,3 @@
1class Admin < User
2 has_many :companies, :finder_sql => 'SELECT * FROM companies'
3end
diff --git a/vendor/plugins/will_paginate/test/fixtures/developer.rb b/vendor/plugins/will_paginate/test/fixtures/developer.rb
new file mode 100644
index 0000000..0224f4b
--- /dev/null
+++ b/vendor/plugins/will_paginate/test/fixtures/developer.rb
@@ -0,0 +1,14 @@
1class Developer < User
2 has_and_belongs_to_many :projects, :include => :topics, :order => 'projects.name'
3
4 def self.with_poor_ones(&block)
5 with_scope :find => { :conditions => ['salary <= ?', 80000], :order => 'salary' } do
6 yield
7 end
8 end
9
10 named_scope :distinct, :select => 'DISTINCT `users`.*'
11 named_scope :poor, :conditions => ['salary <= ?', 80000], :order => 'salary'
12
13 def self.per_page() 10 end
14end
diff --git a/vendor/plugins/will_paginate/test/fixtures/developers_projects.yml b/vendor/plugins/will_paginate/test/fixtures/developers_projects.yml
new file mode 100644
index 0000000..cee359c
--- /dev/null
+++ b/vendor/plugins/will_paginate/test/fixtures/developers_projects.yml
@@ -0,0 +1,13 @@
1david_action_controller:
2 developer_id: 1
3 project_id: 2
4 joined_on: 2004-10-10
5
6david_active_record:
7 developer_id: 1
8 project_id: 1
9 joined_on: 2004-10-10
10
11jamis_active_record:
12 developer_id: 2
13 project_id: 1 \ No newline at end of file
diff --git a/vendor/plugins/will_paginate/test/fixtures/project.rb b/vendor/plugins/will_paginate/test/fixtures/project.rb
new file mode 100644
index 0000000..0f85ef5
--- /dev/null
+++ b/vendor/plugins/will_paginate/test/fixtures/project.rb
@@ -0,0 +1,15 @@
1class Project < ActiveRecord::Base
2 has_and_belongs_to_many :developers, :uniq => true
3
4 has_many :topics
5 # :finder_sql => 'SELECT * FROM topics WHERE (topics.project_id = #{id})',
6 # :counter_sql => 'SELECT COUNT(*) FROM topics WHERE (topics.project_id = #{id})'
7
8 has_many :replies, :through => :topics do
9 def find_recent(params = {})
10 with_scope :find => { :conditions => ['replies.created_at > ?', 15.minutes.ago] } do
11 find :all, params
12 end
13 end
14 end
15end
diff --git a/vendor/plugins/will_paginate/test/fixtures/projects.yml b/vendor/plugins/will_paginate/test/fixtures/projects.yml
new file mode 100644
index 0000000..74f3c32
--- /dev/null
+++ b/vendor/plugins/will_paginate/test/fixtures/projects.yml
@@ -0,0 +1,6 @@
1active_record:
2 id: 1
3 name: Active Record
4action_controller:
5 id: 2
6 name: Active Controller
diff --git a/vendor/plugins/will_paginate/test/fixtures/replies.yml b/vendor/plugins/will_paginate/test/fixtures/replies.yml
new file mode 100644
index 0000000..9a83c00
--- /dev/null
+++ b/vendor/plugins/will_paginate/test/fixtures/replies.yml
@@ -0,0 +1,29 @@
1witty_retort:
2 id: 1
3 topic_id: 1
4 content: Birdman is better!
5 created_at: <%= 6.hours.ago.to_s(:db) %>
6
7another:
8 id: 2
9 topic_id: 2
10 content: Nuh uh!
11 created_at: <%= 1.hour.ago.to_s(:db) %>
12
13spam:
14 id: 3
15 topic_id: 1
16 content: Nice site!
17 created_at: <%= 1.hour.ago.to_s(:db) %>
18
19decisive:
20 id: 4
21 topic_id: 4
22 content: "I'm getting to the bottom of this"
23 created_at: <%= 30.minutes.ago.to_s(:db) %>
24
25brave:
26 id: 5
27 topic_id: 4
28 content: "AR doesn't scare me a bit"
29 created_at: <%= 10.minutes.ago.to_s(:db) %>
diff --git a/vendor/plugins/will_paginate/test/fixtures/reply.rb b/vendor/plugins/will_paginate/test/fixtures/reply.rb
new file mode 100644
index 0000000..ecaf3c1
--- /dev/null
+++ b/vendor/plugins/will_paginate/test/fixtures/reply.rb
@@ -0,0 +1,7 @@
1class Reply < ActiveRecord::Base
2 belongs_to :topic, :include => [:replies]
3
4 named_scope :recent, :conditions => ['replies.created_at > ?', 15.minutes.ago]
5
6 validates_presence_of :content
7end
diff --git a/vendor/plugins/will_paginate/test/fixtures/topic.rb b/vendor/plugins/will_paginate/test/fixtures/topic.rb
new file mode 100644
index 0000000..2c2ce72
--- /dev/null
+++ b/vendor/plugins/will_paginate/test/fixtures/topic.rb
@@ -0,0 +1,10 @@
1class Topic < ActiveRecord::Base
2 has_many :replies, :dependent => :destroy, :order => 'replies.created_at DESC'
3 belongs_to :project
4
5 named_scope :mentions_activerecord, :conditions => ['topics.title LIKE ?', '%ActiveRecord%']
6
7 named_scope :with_replies_starting_with, lambda { |text|
8 { :conditions => "replies.content LIKE '#{text}%' ", :include => :replies }
9 }
10end
diff --git a/vendor/plugins/will_paginate/test/fixtures/topics.yml b/vendor/plugins/will_paginate/test/fixtures/topics.yml
new file mode 100644
index 0000000..0a26904
--- /dev/null
+++ b/vendor/plugins/will_paginate/test/fixtures/topics.yml
@@ -0,0 +1,30 @@
1futurama:
2 id: 1
3 title: Isnt futurama awesome?
4 subtitle: It really is, isnt it.
5 content: I like futurama
6 created_at: <%= 1.day.ago.to_s(:db) %>
7 updated_at:
8
9harvey_birdman:
10 id: 2
11 title: Harvey Birdman is the king of all men
12 subtitle: yup
13 content: He really is
14 created_at: <%= 2.hours.ago.to_s(:db) %>
15 updated_at:
16
17rails:
18 id: 3
19 project_id: 1
20 title: Rails is nice
21 subtitle: It makes me happy
22 content: except when I have to hack internals to fix pagination. even then really.
23 created_at: <%= 20.minutes.ago.to_s(:db) %>
24
25ar:
26 id: 4
27 project_id: 1
28 title: ActiveRecord sometimes freaks me out
29 content: "I mean, what's the deal with eager loading?"
30 created_at: <%= 15.minutes.ago.to_s(:db) %>
diff --git a/vendor/plugins/will_paginate/test/fixtures/user.rb b/vendor/plugins/will_paginate/test/fixtures/user.rb
new file mode 100644
index 0000000..4a57cf0
--- /dev/null
+++ b/vendor/plugins/will_paginate/test/fixtures/user.rb
@@ -0,0 +1,2 @@
1class User < ActiveRecord::Base
2end
diff --git a/vendor/plugins/will_paginate/test/fixtures/users.yml b/vendor/plugins/will_paginate/test/fixtures/users.yml
new file mode 100644
index 0000000..ed2c03a
--- /dev/null
+++ b/vendor/plugins/will_paginate/test/fixtures/users.yml
@@ -0,0 +1,35 @@
1david:
2 id: 1
3 name: David
4 salary: 80000
5 type: Developer
6
7jamis:
8 id: 2
9 name: Jamis
10 salary: 150000
11 type: Developer
12
13<% for digit in 3..10 %>
14dev_<%= digit %>:
15 id: <%= digit %>
16 name: fixture_<%= digit %>
17 salary: 100000
18 type: Developer
19<% end %>
20
21poor_jamis:
22 id: 11
23 name: Jamis
24 salary: 9000
25 type: Developer
26
27admin:
28 id: 12
29 name: admin
30 type: Admin
31
32goofy:
33 id: 13
34 name: Goofy
35 type: Admin
diff --git a/vendor/plugins/will_paginate/test/helper.rb b/vendor/plugins/will_paginate/test/helper.rb
new file mode 100644
index 0000000..ad52b1b
--- /dev/null
+++ b/vendor/plugins/will_paginate/test/helper.rb
@@ -0,0 +1,37 @@
1require 'test/unit'
2require 'rubygems'
3
4# gem install redgreen for colored test output
5begin require 'redgreen'; rescue LoadError; end
6
7require 'boot' unless defined?(ActiveRecord)
8
9class Test::Unit::TestCase
10 protected
11 def assert_respond_to_all object, methods
12 methods.each do |method|
13 [method.to_s, method.to_sym].each { |m| assert_respond_to object, m }
14 end
15 end
16
17 def collect_deprecations
18 old_behavior = WillPaginate::Deprecation.behavior
19 deprecations = []
20 WillPaginate::Deprecation.behavior = Proc.new do |message, callstack|
21 deprecations << message
22 end
23 result = yield
24 [result, deprecations]
25 ensure
26 WillPaginate::Deprecation.behavior = old_behavior
27 end
28end
29
30# Wrap tests that use Mocha and skip if unavailable.
31def uses_mocha(test_name)
32 require 'mocha' unless Object.const_defined?(:Mocha)
33rescue LoadError => load_error
34 $stderr.puts "Skipping #{test_name} tests. `gem install mocha` and try again."
35else
36 yield
37end
diff --git a/vendor/plugins/will_paginate/test/lib/activerecord_test_case.rb b/vendor/plugins/will_paginate/test/lib/activerecord_test_case.rb
new file mode 100644
index 0000000..8f66ebe
--- /dev/null
+++ b/vendor/plugins/will_paginate/test/lib/activerecord_test_case.rb
@@ -0,0 +1,36 @@
1require 'lib/activerecord_test_connector'
2
3class ActiveRecordTestCase < Test::Unit::TestCase
4 # Set our fixture path
5 if ActiveRecordTestConnector.able_to_connect
6 self.fixture_path = File.join(File.dirname(__FILE__), '..', 'fixtures')
7 self.use_transactional_fixtures = true
8 end
9
10 def self.fixtures(*args)
11 super if ActiveRecordTestConnector.connected
12 end
13
14 def run(*args)
15 super if ActiveRecordTestConnector.connected
16 end
17
18 # Default so Test::Unit::TestCase doesn't complain
19 def test_truth
20 end
21
22 protected
23
24 def assert_queries(num = 1)
25 $query_count = 0
26 yield
27 ensure
28 assert_equal num, $query_count, "#{$query_count} instead of #{num} queries were executed."
29 end
30
31 def assert_no_queries(&block)
32 assert_queries(0, &block)
33 end
34end
35
36ActiveRecordTestConnector.setup
diff --git a/vendor/plugins/will_paginate/test/lib/activerecord_test_connector.rb b/vendor/plugins/will_paginate/test/lib/activerecord_test_connector.rb
new file mode 100644
index 0000000..1130cf5
--- /dev/null
+++ b/vendor/plugins/will_paginate/test/lib/activerecord_test_connector.rb
@@ -0,0 +1,75 @@
1require 'active_record'
2require 'active_record/version'
3require 'active_record/fixtures'
4
5class ActiveRecordTestConnector
6 cattr_accessor :able_to_connect
7 cattr_accessor :connected
8
9 FIXTURES_PATH = File.join(File.dirname(__FILE__), '..', 'fixtures')
10
11 # Set our defaults
12 self.connected = false
13 self.able_to_connect = true
14
15 def self.setup
16 unless self.connected || !self.able_to_connect
17 setup_connection
18 load_schema
19 add_load_path FIXTURES_PATH
20 self.connected = true
21 end
22 rescue Exception => e # errors from ActiveRecord setup
23 $stderr.puts "\nSkipping ActiveRecord tests: #{e}\n\n"
24 self.able_to_connect = false
25 end
26
27 private
28
29 def self.add_load_path(path)
30 dep = defined?(ActiveSupport::Dependencies) ? ActiveSupport::Dependencies : ::Dependencies
31 dep.load_paths.unshift path
32 end
33
34 def self.setup_connection
35 db = ENV['DB'].blank?? 'sqlite3' : ENV['DB']
36
37 configurations = YAML.load_file(File.join(File.dirname(__FILE__), '..', 'database.yml'))
38 raise "no configuration for '#{db}'" unless configurations.key? db
39 configuration = configurations[db]
40
41 ActiveRecord::Base.logger = Logger.new(STDOUT) if $0 == 'irb'
42 puts "using #{configuration['adapter']} adapter" unless ENV['DB'].blank?
43
44 gem 'sqlite3-ruby' if 'sqlite3' == db
45
46 ActiveRecord::Base.establish_connection(configuration)
47 ActiveRecord::Base.configurations = { db => configuration }
48 prepare ActiveRecord::Base.connection
49
50 unless Object.const_defined?(:QUOTED_TYPE)
51 Object.send :const_set, :QUOTED_TYPE, ActiveRecord::Base.connection.quote_column_name('type')
52 end
53 end
54
55 def self.load_schema
56 ActiveRecord::Base.silence do
57 ActiveRecord::Migration.verbose = false
58 load File.join(FIXTURES_PATH, 'schema.rb')
59 end
60 end
61
62 def self.prepare(conn)
63 class << conn
64 IGNORED_SQL = [/^PRAGMA/, /^SELECT currval/, /^SELECT CAST/, /^SELECT @@IDENTITY/, /^SELECT @@ROWCOUNT/, /^SHOW FIELDS /]
65
66 def execute_with_counting(sql, name = nil, &block)
67 $query_count ||= 0
68 $query_count += 1 unless IGNORED_SQL.any? { |r| sql =~ r }
69 execute_without_counting(sql, name, &block)
70 end
71
72 alias_method_chain :execute, :counting
73 end
74 end
75end
diff --git a/vendor/plugins/will_paginate/test/lib/load_fixtures.rb b/vendor/plugins/will_paginate/test/lib/load_fixtures.rb
new file mode 100644
index 0000000..10d6f42
--- /dev/null
+++ b/vendor/plugins/will_paginate/test/lib/load_fixtures.rb
@@ -0,0 +1,11 @@
1require 'boot'
2require 'lib/activerecord_test_connector'
3
4# setup the connection
5ActiveRecordTestConnector.setup
6
7# load all fixtures
8Fixtures.create_fixtures(ActiveRecordTestConnector::FIXTURES_PATH, ActiveRecord::Base.connection.tables)
9
10require 'will_paginate'
11WillPaginate.enable_activerecord
diff --git a/vendor/plugins/will_paginate/test/lib/view_test_process.rb b/vendor/plugins/will_paginate/test/lib/view_test_process.rb
new file mode 100644
index 0000000..508411e
--- /dev/null
+++ b/vendor/plugins/will_paginate/test/lib/view_test_process.rb
@@ -0,0 +1,171 @@
1require 'action_controller'
2require 'action_controller/test_process'
3
4require 'will_paginate'
5WillPaginate.enable_actionpack
6
7ActionController::Routing::Routes.draw do |map|
8 map.connect 'dummy/page/:page', :controller => 'dummy'
9 map.connect 'dummy/dots/page.:page', :controller => 'dummy', :action => 'dots'
10 map.connect 'ibocorp/:page', :controller => 'ibocorp',
11 :requirements => { :page => /\d+/ },
12 :defaults => { :page => 1 }
13
14 map.connect ':controller/:action/:id'
15end
16
17ActionController::Base.perform_caching = false
18
19class WillPaginate::ViewTestCase < Test::Unit::TestCase
20 def setup
21 super
22 @controller = DummyController.new
23 @request = @controller.request
24 @html_result = nil
25 @template = '<%= will_paginate collection, options %>'
26
27 @view = ActionView::Base.new
28 @view.assigns['controller'] = @controller
29 @view.assigns['_request'] = @request
30 @view.assigns['_params'] = @request.params
31 end
32
33 def test_no_complain; end
34
35 protected
36
37 def paginate(collection = {}, options = {}, &block)
38 if collection.instance_of? Hash
39 page_options = { :page => 1, :total_entries => 11, :per_page => 4 }.merge(collection)
40 collection = [1].paginate(page_options)
41 end
42
43 locals = { :collection => collection, :options => options }
44
45 unless @view.respond_to? :render_template
46 # Rails 2.2
47 @html_result = ActionView::InlineTemplate.new(@template).render(@view, locals)
48 else
49 if defined? ActionView::InlineTemplate
50 # Rails 2.1
51 args = [ ActionView::InlineTemplate.new(@view, @template, locals) ]
52 else
53 # older Rails versions
54 args = [nil, @template, nil, locals]
55 end
56
57 @html_result = @view.render_template(*args)
58 end
59
60 @html_document = HTML::Document.new(@html_result, true, false)
61
62 if block_given?
63 classname = options[:class] || WillPaginate::ViewHelpers.pagination_options[:class]
64 assert_select("div.#{classname}", 1, 'no main DIV', &block)
65 end
66 end
67
68 def response_from_page_or_rjs
69 @html_document.root
70 end
71
72 def validate_page_numbers expected, links, param_name = :page
73 param_pattern = /\W#{CGI.escape(param_name.to_s)}=([^&]*)/
74
75 assert_equal(expected, links.map { |e|
76 e['href'] =~ param_pattern
77 $1 ? $1.to_i : $1
78 })
79 end
80
81 def assert_links_match pattern, links = nil, numbers = nil
82 links ||= assert_select 'div.pagination a[href]' do |elements|
83 elements
84 end
85
86 pages = [] if numbers
87
88 links.each do |el|
89 assert_match pattern, el['href']
90 if numbers
91 el['href'] =~ pattern
92 pages << ($1.nil?? nil : $1.to_i)
93 end
94 end
95
96 assert_equal numbers, pages, "page numbers don't match" if numbers
97 end
98
99 def assert_no_links_match pattern
100 assert_select 'div.pagination a[href]' do |elements|
101 elements.each do |el|
102 assert_no_match pattern, el['href']
103 end
104 end
105 end
106end
107
108class DummyRequest
109 attr_accessor :symbolized_path_parameters
110
111 def initialize
112 @get = true
113 @params = {}
114 @symbolized_path_parameters = { :controller => 'foo', :action => 'bar' }
115 end
116
117 def get?
118 @get
119 end
120
121 def post
122 @get = false
123 end
124
125 def relative_url_root
126 ''
127 end
128
129 def params(more = nil)
130 @params.update(more) if more
131 @params
132 end
133end
134
135class DummyController
136 attr_reader :request
137 attr_accessor :controller_name
138
139 def initialize
140 @request = DummyRequest.new
141 @url = ActionController::UrlRewriter.new(@request, @request.params)
142 end
143
144 def params
145 @request.params
146 end
147
148 def url_for(params)
149 @url.rewrite(params)
150 end
151end
152
153module HTML
154 Node.class_eval do
155 def inner_text
156 children.map(&:inner_text).join('')
157 end
158 end
159
160 Text.class_eval do
161 def inner_text
162 self.to_s
163 end
164 end
165
166 Tag.class_eval do
167 def inner_text
168 childless?? '' : super
169 end
170 end
171end
diff --git a/vendor/plugins/will_paginate/test/tasks.rake b/vendor/plugins/will_paginate/test/tasks.rake
new file mode 100644
index 0000000..59f2f94
--- /dev/null
+++ b/vendor/plugins/will_paginate/test/tasks.rake
@@ -0,0 +1,59 @@
1require 'rake/testtask'
2
3desc 'Test the will_paginate plugin.'
4Rake::TestTask.new(:test) do |t|
5 t.pattern = 'test/**/*_test.rb'
6 t.verbose = true
7 t.libs << 'test'
8end
9
10# I want to specify environment variables at call time
11class EnvTestTask < Rake::TestTask
12 attr_accessor :env
13
14 def ruby(*args)
15 env.each { |key, value| ENV[key] = value } if env
16 super
17 env.keys.each { |key| ENV.delete key } if env
18 end
19end
20
21for configuration in %w( sqlite3 mysql postgres )
22 EnvTestTask.new("test_#{configuration}") do |t|
23 t.pattern = 'test/finder_test.rb'
24 t.verbose = true
25 t.env = { 'DB' => configuration }
26 t.libs << 'test'
27 end
28end
29
30task :test_databases => %w(test_mysql test_sqlite3 test_postgres)
31
32desc %{Test everything on SQLite3, MySQL and PostgreSQL}
33task :test_full => %w(test test_mysql test_postgres)
34
35desc %{Test everything with Rails 2.1.x, 2.0.x & 1.2.x gems}
36task :test_all do
37 all = Rake::Task['test_full']
38 versions = %w(2.1.0 2.0.4 1.2.6)
39 versions.each do |version|
40 ENV['RAILS_VERSION'] = "~> #{version}"
41 all.invoke
42 reset_invoked unless version == versions.last
43 end
44end
45
46def reset_invoked
47 %w( test_full test test_mysql test_postgres ).each do |name|
48 Rake::Task[name].instance_variable_set '@already_invoked', false
49 end
50end
51
52task :rcov do
53 excludes = %w( lib/will_paginate/named_scope*
54 lib/will_paginate/core_ext.rb
55 lib/will_paginate.rb
56 rails* )
57
58 system %[rcov -Itest:lib test/*.rb -x #{excludes.join(',')}]
59end
diff --git a/vendor/plugins/will_paginate/test/view_test.rb b/vendor/plugins/will_paginate/test/view_test.rb
new file mode 100644
index 0000000..3ada457
--- /dev/null
+++ b/vendor/plugins/will_paginate/test/view_test.rb
@@ -0,0 +1,365 @@
1require 'helper'
2require 'lib/view_test_process'
3
4class AdditionalLinkAttributesRenderer < WillPaginate::LinkRenderer
5 def initialize(link_attributes = nil)
6 super()
7 @additional_link_attributes = link_attributes || { :default => 'true' }
8 end
9
10 def page_link(page, text, attributes = {})
11 @template.link_to text, url_for(page), attributes.merge(@additional_link_attributes)
12 end
13end
14
15class ViewTest < WillPaginate::ViewTestCase
16
17 ## basic pagination ##
18
19 def test_will_paginate
20 paginate do |pagination|
21 assert_select 'a[href]', 3 do |elements|
22 validate_page_numbers [2,3,2], elements
23 assert_select elements.last, ':last-child', "Next &raquo;"
24 end
25 assert_select 'span', 2
26 assert_select 'span.disabled:first-child', '&laquo; Previous'
27 assert_select 'span.current', '1'
28 assert_equal '&laquo; Previous 1 2 3 Next &raquo;', pagination.first.inner_text
29 end
30 end
31
32 def test_no_pagination_when_page_count_is_one
33 paginate :per_page => 30
34 assert_equal '', @html_result
35 end
36
37 def test_will_paginate_with_options
38 paginate({ :page => 2 },
39 :class => 'will_paginate', :previous_label => 'Prev', :next_label => 'Next') do
40 assert_select 'a[href]', 4 do |elements|
41 validate_page_numbers [1,1,3,3], elements
42 # test rel attribute values:
43 assert_select elements[1], 'a', '1' do |link|
44 assert_equal 'prev start', link.first['rel']
45 end
46 assert_select elements.first, 'a', "Prev" do |link|
47 assert_equal 'prev start', link.first['rel']
48 end
49 assert_select elements.last, 'a', "Next" do |link|
50 assert_equal 'next', link.first['rel']
51 end
52 end
53 assert_select 'span.current', '2'
54 end
55 end
56
57 def test_will_paginate_using_renderer_class
58 paginate({}, :renderer => AdditionalLinkAttributesRenderer) do
59 assert_select 'a[default=true]', 3
60 end
61 end
62
63 def test_will_paginate_using_renderer_instance
64 renderer = WillPaginate::LinkRenderer.new
65 renderer.gap_marker = '<span class="my-gap">~~</span>'
66
67 paginate({ :per_page => 2 }, :inner_window => 0, :outer_window => 0, :renderer => renderer) do
68 assert_select 'span.my-gap', '~~'
69 end
70
71 renderer = AdditionalLinkAttributesRenderer.new(:title => 'rendered')
72 paginate({}, :renderer => renderer) do
73 assert_select 'a[title=rendered]', 3
74 end
75 end
76
77 def test_prev_next_links_have_classnames
78 paginate do |pagination|
79 assert_select 'span.disabled.prev_page:first-child'
80 assert_select 'a.next_page[href]:last-child'
81 end
82 end
83
84 def test_prev_label_deprecated
85 assert_deprecated ':previous_label' do
86 paginate({ :page => 2 }, :prev_label => 'Deprecated') do
87 assert_select 'a[href]:first-child', 'Deprecated'
88 end
89 end
90 end
91
92 def test_full_output
93 paginate
94 expected = <<-HTML
95 <div class="pagination"><span class="disabled prev_page">&laquo; Previous</span>
96 <span class="current">1</span>
97 <a href="/foo/bar?page=2" rel="next">2</a>
98 <a href="/foo/bar?page=3">3</a>
99 <a href="/foo/bar?page=2" class="next_page" rel="next">Next &raquo;</a></div>
100 HTML
101 expected.strip!.gsub!(/\s{2,}/, ' ')
102
103 assert_dom_equal expected, @html_result
104 end
105
106 def test_escaping_of_urls
107 paginate({:page => 1, :per_page => 1, :total_entries => 2},
108 :page_links => false, :params => { :tag => '<br>' })
109
110 assert_select 'a[href]', 1 do |links|
111 query = links.first['href'].split('?', 2)[1]
112 assert_equal %w(page=2 tag=%3Cbr%3E), query.split('&amp;').sort
113 end
114 end
115
116 ## advanced options for pagination ##
117
118 def test_will_paginate_without_container
119 paginate({}, :container => false)
120 assert_select 'div.pagination', 0, 'main DIV present when it shouldn\'t'
121 assert_select 'a[href]', 3
122 end
123
124 def test_will_paginate_without_page_links
125 paginate({ :page => 2 }, :page_links => false) do
126 assert_select 'a[href]', 2 do |elements|
127 validate_page_numbers [1,3], elements
128 end
129 end
130 end
131
132 def test_will_paginate_windows
133 paginate({ :page => 6, :per_page => 1 }, :inner_window => 1) do |pagination|
134 assert_select 'a[href]', 8 do |elements|
135 validate_page_numbers [5,1,2,5,7,10,11,7], elements
136 assert_select elements.first, 'a', '&laquo; Previous'
137 assert_select elements.last, 'a', 'Next &raquo;'
138 end
139 assert_select 'span.current', '6'
140 assert_equal '&laquo; Previous 1 2 &hellip; 5 6 7 &hellip; 10 11 Next &raquo;', pagination.first.inner_text
141 end
142 end
143
144 def test_will_paginate_eliminates_small_gaps
145 paginate({ :page => 6, :per_page => 1 }, :inner_window => 2) do
146 assert_select 'a[href]', 12 do |elements|
147 validate_page_numbers [5,1,2,3,4,5,7,8,9,10,11,7], elements
148 end
149 end
150 end
151
152 def test_container_id
153 paginate do |div|
154 assert_nil div.first['id']
155 end
156
157 # magic ID
158 paginate({}, :id => true) do |div|
159 assert_equal 'fixnums_pagination', div.first['id']
160 end
161
162 # explicit ID
163 paginate({}, :id => 'custom_id') do |div|
164 assert_equal 'custom_id', div.first['id']
165 end
166 end
167
168 ## other helpers ##
169
170 def test_paginated_section
171 @template = <<-ERB
172 <% paginated_section collection, options do %>
173 <%= content_tag :div, '', :id => "developers" %>
174 <% end %>
175 ERB
176
177 paginate
178 assert_select 'div.pagination', 2
179 assert_select 'div.pagination + div#developers', 1
180 end
181
182 def test_page_entries_info
183 @template = '<%= page_entries_info collection %>'
184 array = ('a'..'z').to_a
185
186 paginate array.paginate(:page => 2, :per_page => 5)
187 assert_equal %{Displaying strings <b>6&nbsp;-&nbsp;10</b> of <b>26</b> in total},
188 @html_result
189
190 paginate array.paginate(:page => 7, :per_page => 4)
191 assert_equal %{Displaying strings <b>25&nbsp;-&nbsp;26</b> of <b>26</b> in total},
192 @html_result
193 end
194
195 uses_mocha 'class name' do
196 def test_page_entries_info_with_longer_class_name
197 @template = '<%= page_entries_info collection %>'
198 collection = ('a'..'z').to_a.paginate
199 collection.first.stubs(:class).returns(mock('class', :name => 'ProjectType'))
200
201 paginate collection
202 assert @html_result.index('project types'), "expected <#{@html_result.inspect}> to mention 'project types'"
203 end
204 end
205
206 def test_page_entries_info_with_single_page_collection
207 @template = '<%= page_entries_info collection %>'
208
209 paginate(('a'..'d').to_a.paginate(:page => 1, :per_page => 5))
210 assert_equal %{Displaying <b>all 4</b> strings}, @html_result
211
212 paginate(['a'].paginate(:page => 1, :per_page => 5))
213 assert_equal %{Displaying <b>1</b> string}, @html_result
214
215 paginate([].paginate(:page => 1, :per_page => 5))
216 assert_equal %{No entries found}, @html_result
217 end
218
219 def test_page_entries_info_with_custom_entry_name
220 @template = '<%= page_entries_info collection, :entry_name => "author" %>'
221
222 entries = (1..20).to_a
223
224 paginate(entries.paginate(:page => 1, :per_page => 5))
225 assert_equal %{Displaying authors <b>1&nbsp;-&nbsp;5</b> of <b>20</b> in total}, @html_result
226
227 paginate(entries.paginate(:page => 1, :per_page => 20))
228 assert_equal %{Displaying <b>all 20</b> authors}, @html_result
229
230 paginate(['a'].paginate(:page => 1, :per_page => 5))
231 assert_equal %{Displaying <b>1</b> author}, @html_result
232
233 paginate([].paginate(:page => 1, :per_page => 5))
234 assert_equal %{No authors found}, @html_result
235 end
236
237 ## parameter handling in page links ##
238
239 def test_will_paginate_preserves_parameters_on_get
240 @request.params :foo => { :bar => 'baz' }
241 paginate
242 assert_links_match /foo%5Bbar%5D=baz/
243 end
244
245 def test_will_paginate_doesnt_preserve_parameters_on_post
246 @request.post
247 @request.params :foo => 'bar'
248 paginate
249 assert_no_links_match /foo=bar/
250 end
251
252 def test_adding_additional_parameters
253 paginate({}, :params => { :foo => 'bar' })
254 assert_links_match /foo=bar/
255 end
256
257 def test_adding_anchor_parameter
258 paginate({}, :params => { :anchor => 'anchor' })
259 assert_links_match /#anchor$/
260 end
261
262 def test_removing_arbitrary_parameters
263 @request.params :foo => 'bar'
264 paginate({}, :params => { :foo => nil })
265 assert_no_links_match /foo=bar/
266 end
267
268 def test_adding_additional_route_parameters
269 paginate({}, :params => { :controller => 'baz', :action => 'list' })
270 assert_links_match %r{\Wbaz/list\W}
271 end
272
273 def test_will_paginate_with_custom_page_param
274 paginate({ :page => 2 }, :param_name => :developers_page) do
275 assert_select 'a[href]', 4 do |elements|
276 validate_page_numbers [1,1,3,3], elements, :developers_page
277 end
278 end
279 end
280
281 def test_complex_custom_page_param
282 @request.params :developers => { :page => 2 }
283
284 paginate({ :page => 2 }, :param_name => 'developers[page]') do
285 assert_select 'a[href]', 4 do |links|
286 assert_links_match /\?developers%5Bpage%5D=\d+$/, links
287 validate_page_numbers [1,1,3,3], links, 'developers[page]'
288 end
289 end
290 end
291
292 def test_custom_routing_page_param
293 @request.symbolized_path_parameters.update :controller => 'dummy', :action => nil
294 paginate :per_page => 2 do
295 assert_select 'a[href]', 6 do |links|
296 assert_links_match %r{/page/(\d+)$}, links, [2, 3, 4, 5, 6, 2]
297 end
298 end
299 end
300
301 def test_custom_routing_page_param_with_dot_separator
302 @request.symbolized_path_parameters.update :controller => 'dummy', :action => 'dots'
303 paginate :per_page => 2 do
304 assert_select 'a[href]', 6 do |links|
305 assert_links_match %r{/page\.(\d+)$}, links, [2, 3, 4, 5, 6, 2]
306 end
307 end
308 end
309
310 def test_custom_routing_with_first_page_hidden
311 @request.symbolized_path_parameters.update :controller => 'ibocorp', :action => nil
312 paginate :page => 2, :per_page => 2 do
313 assert_select 'a[href]', 7 do |links|
314 assert_links_match %r{/ibocorp(?:/(\d+))?$}, links, [nil, nil, 3, 4, 5, 6, 3]
315 end
316 end
317 end
318
319 ## internal hardcore stuff ##
320
321 class LegacyCollection < WillPaginate::Collection
322 alias :page_count :total_pages
323 undef :total_pages
324 end
325
326 def test_deprecation_notices_with_page_count
327 collection = LegacyCollection.new(1, 1, 2)
328
329 assert_deprecated collection.class.name do
330 paginate collection
331 end
332 end
333
334 uses_mocha 'view internals' do
335 def test_collection_name_can_be_guessed
336 collection = mock
337 collection.expects(:total_pages).returns(1)
338
339 @template = '<%= will_paginate options %>'
340 @controller.controller_name = 'developers'
341 @view.assigns['developers'] = collection
342
343 paginate(nil)
344 end
345 end
346
347 def test_inferred_collection_name_raises_error_when_nil
348 @template = '<%= will_paginate options %>'
349 @controller.controller_name = 'developers'
350
351 e = assert_raise ArgumentError do
352 paginate(nil)
353 end
354 assert e.message.include?('@developers')
355 end
356
357 if ActionController::Base.respond_to? :rescue_responses
358 # only on Rails 2
359 def test_rescue_response_hook_presence
360 assert_equal :not_found,
361 ActionController::Base.rescue_responses['WillPaginate::InvalidPage']
362 end
363 end
364
365end
diff --git a/vendor/plugins/will_paginate/will_paginate.gemspec b/vendor/plugins/will_paginate/will_paginate.gemspec
new file mode 100644
index 0000000..1072c3a
--- /dev/null
+++ b/vendor/plugins/will_paginate/will_paginate.gemspec
@@ -0,0 +1,20 @@
1Gem::Specification.new do |s|
2 s.name = 'will_paginate'
3 s.version = '2.3.7'
4 s.date = '2009-02-10'
5
6 s.summary = "Most awesome pagination solution for Rails"
7 s.description = "The will_paginate library provides a simple, yet powerful and extensible API for ActiveRecord pagination and rendering of pagination links in ActionView templates."
8
9 s.authors = ['Mislav Marohnić', 'PJ Hyett']
10 s.email = 'mislav.marohnic@gmail.com'
11 s.homepage = 'http://github.com/mislav/will_paginate/wikis'
12
13 s.has_rdoc = true
14 s.rdoc_options = ['--main', 'README.rdoc']
15 s.rdoc_options << '--inline-source' << '--charset=UTF-8'
16 s.extra_rdoc_files = ['README.rdoc', 'LICENSE', 'CHANGELOG.rdoc']
17
18 s.files = %w(CHANGELOG.rdoc LICENSE README.rdoc Rakefile examples examples/apple-circle.gif examples/index.haml examples/index.html examples/pagination.css examples/pagination.sass init.rb lib lib/will_paginate lib/will_paginate.rb lib/will_paginate/array.rb lib/will_paginate/collection.rb lib/will_paginate/core_ext.rb lib/will_paginate/finder.rb lib/will_paginate/named_scope.rb lib/will_paginate/named_scope_patch.rb lib/will_paginate/version.rb lib/will_paginate/view_helpers.rb test test/boot.rb test/collection_test.rb test/console test/database.yml test/finder_test.rb test/fixtures test/fixtures/admin.rb test/fixtures/developer.rb test/fixtures/developers_projects.yml test/fixtures/project.rb test/fixtures/projects.yml test/fixtures/replies.yml test/fixtures/reply.rb test/fixtures/schema.rb test/fixtures/topic.rb test/fixtures/topics.yml test/fixtures/user.rb test/fixtures/users.yml test/helper.rb test/lib test/lib/activerecord_test_case.rb test/lib/activerecord_test_connector.rb test/lib/load_fixtures.rb test/lib/view_test_process.rb test/tasks.rake test/view_test.rb)
19 s.test_files = %w(test/boot.rb test/collection_test.rb test/console test/database.yml test/finder_test.rb test/fixtures test/fixtures/admin.rb test/fixtures/developer.rb test/fixtures/developers_projects.yml test/fixtures/project.rb test/fixtures/projects.yml test/fixtures/replies.yml test/fixtures/reply.rb test/fixtures/schema.rb test/fixtures/topic.rb test/fixtures/topics.yml test/fixtures/user.rb test/fixtures/users.yml test/helper.rb test/lib test/lib/activerecord_test_case.rb test/lib/activerecord_test_connector.rb test/lib/load_fixtures.rb test/lib/view_test_process.rb test/tasks.rake test/view_test.rb)
20end