diff options
| author | hukl <contact@smyck.org> | 2009-02-17 12:47:49 +0100 |
|---|---|---|
| committer | hukl <contact@smyck.org> | 2009-02-17 12:47:49 +0100 |
| commit | 3cdcb5ca02a94b2b342c30903a27d47d35d46e55 (patch) | |
| tree | ef3e1154fe262561b3955c07edcaee3824a21f47 /vendor | |
| parent | 7a282f2605f6fb3689940e5c7072b4801653deb2 (diff) | |
added will_paginate plugin
Diffstat (limited to 'vendor')
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 @@ | |||
| 1 | CHANGELOG.rdoc | ||
| 2 | LICENSE | ||
| 3 | README.rdoc | ||
| 4 | Rakefile | ||
| 5 | examples | ||
| 6 | examples/apple-circle.gif | ||
| 7 | examples/index.haml | ||
| 8 | examples/index.html | ||
| 9 | examples/pagination.css | ||
| 10 | examples/pagination.sass | ||
| 11 | init.rb | ||
| 12 | lib | ||
| 13 | lib/will_paginate | ||
| 14 | lib/will_paginate.rb | ||
| 15 | lib/will_paginate/array.rb | ||
| 16 | lib/will_paginate/collection.rb | ||
| 17 | lib/will_paginate/core_ext.rb | ||
| 18 | lib/will_paginate/finder.rb | ||
| 19 | lib/will_paginate/named_scope.rb | ||
| 20 | lib/will_paginate/named_scope_patch.rb | ||
| 21 | lib/will_paginate/version.rb | ||
| 22 | lib/will_paginate/view_helpers.rb | ||
| 23 | test | ||
| 24 | test/boot.rb | ||
| 25 | test/collection_test.rb | ||
| 26 | test/console | ||
| 27 | test/database.yml | ||
| 28 | test/finder_test.rb | ||
| 29 | test/fixtures | ||
| 30 | test/fixtures/admin.rb | ||
| 31 | test/fixtures/developer.rb | ||
| 32 | test/fixtures/developers_projects.yml | ||
| 33 | test/fixtures/project.rb | ||
| 34 | test/fixtures/projects.yml | ||
| 35 | test/fixtures/replies.yml | ||
| 36 | test/fixtures/reply.rb | ||
| 37 | test/fixtures/schema.rb | ||
| 38 | test/fixtures/topic.rb | ||
| 39 | test/fixtures/topics.yml | ||
| 40 | test/fixtures/user.rb | ||
| 41 | test/fixtures/users.yml | ||
| 42 | test/helper.rb | ||
| 43 | test/lib | ||
| 44 | test/lib/activerecord_test_case.rb | ||
| 45 | test/lib/activerecord_test_connector.rb | ||
| 46 | test/lib/load_fixtures.rb | ||
| 47 | test/lib/view_test_process.rb | ||
| 48 | test/tasks.rake | ||
| 49 | test/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">…</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 @@ | |||
| 1 | Copyright (c) 2007 PJ Hyett and Mislav Marohnić | ||
| 2 | |||
| 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of | ||
| 4 | this software and associated documentation files (the "Software"), to deal in | ||
| 5 | the Software without restriction, including without limitation the rights to | ||
| 6 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of | ||
| 7 | the Software, and to permit persons to whom the Software is furnished to do so, | ||
| 8 | subject to the following conditions: | ||
| 9 | |||
| 10 | The above copyright notice and this permission notice shall be included in all | ||
| 11 | copies or substantial portions of the Software. | ||
| 12 | |||
| 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
| 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS | ||
| 15 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR | ||
| 16 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER | ||
| 17 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | ||
| 18 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | ||
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 | |||
| 3 | Pagination is just limiting the number of records displayed. Why should you let | ||
| 4 | it get in your way while developing, then? This plugin makes magic happen. Did | ||
| 5 | you 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 | ||
| 10 | can. | ||
| 11 | |||
| 12 | Some 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 | |||
| 23 | Use a paginate finder in the controller: | ||
| 24 | |||
| 25 | @posts = Post.paginate_by_board_id @board.id, :page => params[:page], :order => 'updated_at DESC' | ||
| 26 | |||
| 27 | Yeah, +paginate+ works just like +find+ -- it just doesn't fetch all the | ||
| 28 | records. Don't forget to tell it which page you want, or it will complain! | ||
| 29 | Read more on WillPaginate::Finder::ClassMethods. | ||
| 30 | |||
| 31 | Render the posts in your view like you would normally do. When you need to render | ||
| 32 | pagination, just stick this in: | ||
| 33 | |||
| 34 | <%= will_paginate @posts %> | ||
| 35 | |||
| 36 | You're done. (You can find the option list at WillPaginate::ViewHelpers.) | ||
| 37 | |||
| 38 | How does it know how much items to fetch per page? It asks your model by calling | ||
| 39 | its <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. | ||
| 55 | But you can always specify the count explicitly when calling +paginate+: | ||
| 56 | |||
| 57 | @posts = Post.paginate :page => params[:page], :per_page => 50 | ||
| 58 | |||
| 59 | The +paginate+ finder wraps the original finder and returns your resultset that now has | ||
| 60 | some new properties. You can use the collection as you would with any ActiveRecord | ||
| 61 | resultset. 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 | |||
| 72 | More 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 | |||
| 80 | Authors:: Mislav Marohnić, PJ Hyett | ||
| 81 | Original announcement:: http://errtheblog.com/post/929 | ||
| 82 | Original PHP source:: http://www.strangerstudios.com/sandbox/pagination/diggstyle.php | ||
| 83 | |||
| 84 | All these people helped making will_paginate what it is now with their code | ||
| 85 | contributions or just simply awesome ideas: | ||
| 86 | |||
| 87 | Chris Wanstrath, Dr. Nic Williams, K. Adam Christensen, Mike Garey, Bence | ||
| 88 | Golda, Matt Aimonetti, Charles Brian Quinn, Desi McAdam, James Coglan, Matijs | ||
| 89 | van Zuijlen, Maria, Brendan Ribera, Todd Willey, Bryan Helmkamp, Jan Berkel, | ||
| 90 | Lourens Naudé, Rick Olson, Russell Norris, Piotr Usewicz, Chris Eppstein, | ||
| 91 | Denis Barushev, Ben Pickles. | ||
| 92 | |||
| 93 | |||
| 94 | == Usable pagination in the UI | ||
| 95 | |||
| 96 | There are some CSS styles to get you started in the "examples/" directory. They | ||
| 97 | are {showcased online here}[http://mislav.caboo.se/static/will_paginate/]. | ||
| 98 | |||
| 99 | More 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 | |||
| 105 | Want 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 @@ | |||
| 1 | require 'rubygems' | ||
| 2 | begin | ||
| 3 | hanna_dir = '/Users/mislav/Projects/Hanna/lib' | ||
| 4 | $:.unshift hanna_dir if File.exists? hanna_dir | ||
| 5 | require 'hanna/rdoctask' | ||
| 6 | rescue LoadError | ||
| 7 | require 'rake' | ||
| 8 | require 'rake/rdoctask' | ||
| 9 | end | ||
| 10 | load 'test/tasks.rake' | ||
| 11 | |||
| 12 | desc 'Default: run unit tests.' | ||
| 13 | task :default => :test | ||
| 14 | |||
| 15 | desc 'Generate RDoc documentation for the will_paginate plugin.' | ||
| 16 | Rake::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/' | ||
| 29 | end | ||
| 30 | |||
| 31 | desc %{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.} | ||
| 34 | task :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") } | ||
| 57 | end | ||
| 58 | |||
| 59 | task :examples do | ||
| 60 | %x(haml examples/index.haml examples/index.html) | ||
| 61 | %x(sass examples/pagination.sass examples/pagination.css) | ||
| 62 | end | ||
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">« 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">…</span> <a href="./?page=29">29</a> <a href="./?page=30">30</a> <a href="./?page=2" rel="next" class="next_page">Next »</a>' | ||
| 31 | - pagination_no_page_links = '<span class="disabled prev_page">« Previous</span> <a href="./?page=2" rel="next" class="next_page">Next »</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('<', '<').gsub('>', '>') | ||
| 55 | |||
| 56 | %h2 Digg-style, extra content | ||
| 57 | .digg_pagination | ||
| 58 | .page_info Displaying entries <b>1 - 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('<', '<').gsub('>', '>') | ||
| 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">« 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">…</span> <a href="./?page=29">29</a> <a href="./?page=30">30</a> <a href="./?page=2" rel="next" class="next_page">Next »</a> | ||
| 54 | </div> | ||
| 55 | <h2>Digg.com</h2> | ||
| 56 | <div class='digg_pagination'> | ||
| 57 | <span class="disabled prev_page">« 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">…</span> <a href="./?page=29">29</a> <a href="./?page=30">30</a> <a href="./?page=2" rel="next" class="next_page">Next »</a> | ||
| 58 | </div> | ||
| 59 | <h2>Digg-style, no page links</h2> | ||
| 60 | <div class='digg_pagination'> | ||
| 61 | <span class="disabled prev_page">« Previous</span> <a href="./?page=2" rel="next" class="next_page">Next »</a> | ||
| 62 | </div> | ||
| 63 | <p>Code that renders this:</p> | ||
| 64 | <pre> | ||
| 65 | <code><%= will_paginate @posts, :page_links => false %></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 - 6</b> of <b>180</b> in total | ||
| 71 | </div> | ||
| 72 | <span class="disabled prev_page">« 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">…</span> <a href="./?page=29">29</a> <a href="./?page=30">30</a> <a href="./?page=2" rel="next" class="next_page">Next »</a> | ||
| 73 | </div> | ||
| 74 | <p>Code that renders this:</p> | ||
| 75 | <pre> | ||
| 76 | <code><div class="digg_pagination"> | ||
| 77 | <div clas="page_info"> | ||
| 78 | <%= page_entries_info @posts %> | ||
| 79 | </div> | ||
| 80 | <%= will_paginate @posts, :container => false %> | ||
| 81 | </div></code> | ||
| 82 | </pre> | ||
| 83 | <h2>Apple.com store</h2> | ||
| 84 | <div class='apple_pagination'> | ||
| 85 | <span class="disabled prev_page">« 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">…</span> <a href="./?page=29">29</a> <a href="./?page=30">30</a> <a href="./?page=2" rel="next" class="next_page">Next »</a> | ||
| 86 | </div> | ||
| 87 | <h2>Flickr.com</h2> | ||
| 88 | <div class='flickr_pagination'> | ||
| 89 | <span class="disabled prev_page">« 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">…</span> <a href="./?page=29">29</a> <a href="./?page=30">30</a> <a href="./?page=2" rel="next" class="next_page">Next »</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 @@ | |||
| 1 | require '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! | ||
| 10 | module 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 | ||
| 74 | end | ||
| 75 | |||
| 76 | if defined?(Rails) and defined?(ActiveRecord) and defined?(ActionController) | ||
| 77 | WillPaginate.enable | ||
| 78 | end | ||
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 @@ | |||
| 1 | require 'will_paginate/collection' | ||
| 2 | |||
| 3 | # http://www.desimcadam.com/archives/8 | ||
| 4 | Array.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 | ||
| 16 | end | ||
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 @@ | |||
| 1 | module 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 | ||
| 146 | end | ||
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 @@ | |||
| 1 | require 'set' | ||
| 2 | require 'will_paginate/array' | ||
| 3 | |||
| 4 | unless 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 | ||
| 17 | end | ||
| 18 | |||
| 19 | unless 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 | ||
| 32 | end | ||
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 @@ | |||
| 1 | require 'will_paginate/core_ext' | ||
| 2 | |||
| 3 | module 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 | ||
| 264 | end | ||
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 @@ | |||
| 1 | module 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 | ||
| 170 | end | ||
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 @@ | |||
| 1 | ActiveRecord::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 | ||
| 6 | end | ||
| 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 | ||
| 21 | end | ||
| 22 | |||
| 23 | # Rails 1.2.6 | ||
| 24 | ActiveRecord::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 | ||
| 37 | end 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 @@ | |||
| 1 | module WillPaginate | ||
| 2 | module VERSION | ||
| 3 | MAJOR = 2 | ||
| 4 | MINOR = 3 | ||
| 5 | TINY = 5 | ||
| 6 | |||
| 7 | STRING = [MAJOR, MINOR, TINY].join('.') | ||
| 8 | end | ||
| 9 | end | ||
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 @@ | |||
| 1 | require 'will_paginate/core_ext' | ||
| 2 | |||
| 3 | module 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 => '« Previous', | ||
| 27 | :next_label => 'Next »', | ||
| 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 - %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">…</span> | ||
| 208 | attr_accessor :gap_marker | ||
| 209 | |||
| 210 | def initialize | ||
| 211 | @gap_marker = '<span class="gap">…</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!((?:\?|&)#{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 | ||
| 389 | end | ||
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 @@ | |||
| 1 | plugin_root = File.join(File.dirname(__FILE__), '..') | ||
| 2 | version = ENV['RAILS_VERSION'] | ||
| 3 | version = nil if version and version == "" | ||
| 4 | |||
| 5 | # first look for a symlink to a copy of the framework | ||
| 6 | if !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" | ||
| 10 | else | ||
| 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 | ||
| 21 | end | ||
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 @@ | |||
| 1 | require 'helper' | ||
| 2 | require 'will_paginate/array' | ||
| 3 | |||
| 4 | class 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 | ||
| 143 | end | ||
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 | ||
| 2 | irb = RUBY_PLATFORM =~ /(:?mswin|mingw)/ ? 'irb.bat' : 'irb' | ||
| 3 | libs = [] | ||
| 4 | |||
| 5 | libs << 'irb/completion' | ||
| 6 | libs << File.join('lib', 'load_fixtures') | ||
| 7 | |||
| 8 | exec "#{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 @@ | |||
| 1 | require 'helper' | ||
| 2 | require 'lib/activerecord_test_case' | ||
| 3 | |||
| 4 | require 'will_paginate' | ||
| 5 | WillPaginate.enable_activerecord | ||
| 6 | WillPaginate.enable_named_scope | ||
| 7 | |||
| 8 | class 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 | ||
| 476 | end | ||
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 @@ | |||
| 1 | class Admin < User | ||
| 2 | has_many :companies, :finder_sql => 'SELECT * FROM companies' | ||
| 3 | end | ||
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 @@ | |||
| 1 | class Developer < User | ||
| 2 | has_and_belongs_to_many :projects, :include => :topics, :order => 'projects.name' | ||
| 3 | |||
| 4 | def self.with_poor_ones(&block) | ||
| 5 | with_scope :find => { :conditions => ['salary <= ?', 80000], :order => 'salary' } do | ||
| 6 | yield | ||
| 7 | end | ||
| 8 | end | ||
| 9 | |||
| 10 | named_scope :distinct, :select => 'DISTINCT `users`.*' | ||
| 11 | named_scope :poor, :conditions => ['salary <= ?', 80000], :order => 'salary' | ||
| 12 | |||
| 13 | def self.per_page() 10 end | ||
| 14 | end | ||
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 @@ | |||
| 1 | david_action_controller: | ||
| 2 | developer_id: 1 | ||
| 3 | project_id: 2 | ||
| 4 | joined_on: 2004-10-10 | ||
| 5 | |||
| 6 | david_active_record: | ||
| 7 | developer_id: 1 | ||
| 8 | project_id: 1 | ||
| 9 | joined_on: 2004-10-10 | ||
| 10 | |||
| 11 | jamis_active_record: | ||
| 12 | developer_id: 2 | ||
| 13 | project_id: 1 \ 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 @@ | |||
| 1 | class Project < ActiveRecord::Base | ||
| 2 | has_and_belongs_to_many :developers, :uniq => true | ||
| 3 | |||
| 4 | has_many :topics | ||
| 5 | # :finder_sql => 'SELECT * FROM topics WHERE (topics.project_id = #{id})', | ||
| 6 | # :counter_sql => 'SELECT COUNT(*) FROM topics WHERE (topics.project_id = #{id})' | ||
| 7 | |||
| 8 | has_many :replies, :through => :topics do | ||
| 9 | def find_recent(params = {}) | ||
| 10 | with_scope :find => { :conditions => ['replies.created_at > ?', 15.minutes.ago] } do | ||
| 11 | find :all, params | ||
| 12 | end | ||
| 13 | end | ||
| 14 | end | ||
| 15 | end | ||
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 @@ | |||
| 1 | active_record: | ||
| 2 | id: 1 | ||
| 3 | name: Active Record | ||
| 4 | action_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 @@ | |||
| 1 | witty_retort: | ||
| 2 | id: 1 | ||
| 3 | topic_id: 1 | ||
| 4 | content: Birdman is better! | ||
| 5 | created_at: <%= 6.hours.ago.to_s(:db) %> | ||
| 6 | |||
| 7 | another: | ||
| 8 | id: 2 | ||
| 9 | topic_id: 2 | ||
| 10 | content: Nuh uh! | ||
| 11 | created_at: <%= 1.hour.ago.to_s(:db) %> | ||
| 12 | |||
| 13 | spam: | ||
| 14 | id: 3 | ||
| 15 | topic_id: 1 | ||
| 16 | content: Nice site! | ||
| 17 | created_at: <%= 1.hour.ago.to_s(:db) %> | ||
| 18 | |||
| 19 | decisive: | ||
| 20 | id: 4 | ||
| 21 | topic_id: 4 | ||
| 22 | content: "I'm getting to the bottom of this" | ||
| 23 | created_at: <%= 30.minutes.ago.to_s(:db) %> | ||
| 24 | |||
| 25 | brave: | ||
| 26 | id: 5 | ||
| 27 | topic_id: 4 | ||
| 28 | content: "AR doesn't scare me a bit" | ||
| 29 | created_at: <%= 10.minutes.ago.to_s(:db) %> | ||
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 @@ | |||
| 1 | class 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 | ||
| 7 | end | ||
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 @@ | |||
| 1 | class Topic < ActiveRecord::Base | ||
| 2 | has_many :replies, :dependent => :destroy, :order => 'replies.created_at DESC' | ||
| 3 | belongs_to :project | ||
| 4 | |||
| 5 | named_scope :mentions_activerecord, :conditions => ['topics.title LIKE ?', '%ActiveRecord%'] | ||
| 6 | |||
| 7 | named_scope :with_replies_starting_with, lambda { |text| | ||
| 8 | { :conditions => "replies.content LIKE '#{text}%' ", :include => :replies } | ||
| 9 | } | ||
| 10 | end | ||
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 @@ | |||
| 1 | futurama: | ||
| 2 | id: 1 | ||
| 3 | title: Isnt futurama awesome? | ||
| 4 | subtitle: It really is, isnt it. | ||
| 5 | content: I like futurama | ||
| 6 | created_at: <%= 1.day.ago.to_s(:db) %> | ||
| 7 | updated_at: | ||
| 8 | |||
| 9 | harvey_birdman: | ||
| 10 | id: 2 | ||
| 11 | title: Harvey Birdman is the king of all men | ||
| 12 | subtitle: yup | ||
| 13 | content: He really is | ||
| 14 | created_at: <%= 2.hours.ago.to_s(:db) %> | ||
| 15 | updated_at: | ||
| 16 | |||
| 17 | rails: | ||
| 18 | id: 3 | ||
| 19 | project_id: 1 | ||
| 20 | title: Rails is nice | ||
| 21 | subtitle: It makes me happy | ||
| 22 | content: except when I have to hack internals to fix pagination. even then really. | ||
| 23 | created_at: <%= 20.minutes.ago.to_s(:db) %> | ||
| 24 | |||
| 25 | ar: | ||
| 26 | id: 4 | ||
| 27 | project_id: 1 | ||
| 28 | title: ActiveRecord sometimes freaks me out | ||
| 29 | content: "I mean, what's the deal with eager loading?" | ||
| 30 | created_at: <%= 15.minutes.ago.to_s(:db) %> | ||
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 @@ | |||
| 1 | class User < ActiveRecord::Base | ||
| 2 | end | ||
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 @@ | |||
| 1 | david: | ||
| 2 | id: 1 | ||
| 3 | name: David | ||
| 4 | salary: 80000 | ||
| 5 | type: Developer | ||
| 6 | |||
| 7 | jamis: | ||
| 8 | id: 2 | ||
| 9 | name: Jamis | ||
| 10 | salary: 150000 | ||
| 11 | type: Developer | ||
| 12 | |||
| 13 | <% for digit in 3..10 %> | ||
| 14 | dev_<%= digit %>: | ||
| 15 | id: <%= digit %> | ||
| 16 | name: fixture_<%= digit %> | ||
| 17 | salary: 100000 | ||
| 18 | type: Developer | ||
| 19 | <% end %> | ||
| 20 | |||
| 21 | poor_jamis: | ||
| 22 | id: 11 | ||
| 23 | name: Jamis | ||
| 24 | salary: 9000 | ||
| 25 | type: Developer | ||
| 26 | |||
| 27 | admin: | ||
| 28 | id: 12 | ||
| 29 | name: admin | ||
| 30 | type: Admin | ||
| 31 | |||
| 32 | goofy: | ||
| 33 | id: 13 | ||
| 34 | name: Goofy | ||
| 35 | type: Admin | ||
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 @@ | |||
| 1 | require 'test/unit' | ||
| 2 | require 'rubygems' | ||
| 3 | |||
| 4 | # gem install redgreen for colored test output | ||
| 5 | begin require 'redgreen'; rescue LoadError; end | ||
| 6 | |||
| 7 | require 'boot' unless defined?(ActiveRecord) | ||
| 8 | |||
| 9 | class Test::Unit::TestCase | ||
| 10 | protected | ||
| 11 | def assert_respond_to_all object, methods | ||
| 12 | methods.each do |method| | ||
| 13 | [method.to_s, method.to_sym].each { |m| assert_respond_to object, m } | ||
| 14 | end | ||
| 15 | end | ||
| 16 | |||
| 17 | def collect_deprecations | ||
| 18 | old_behavior = WillPaginate::Deprecation.behavior | ||
| 19 | deprecations = [] | ||
| 20 | WillPaginate::Deprecation.behavior = Proc.new do |message, callstack| | ||
| 21 | deprecations << message | ||
| 22 | end | ||
| 23 | result = yield | ||
| 24 | [result, deprecations] | ||
| 25 | ensure | ||
| 26 | WillPaginate::Deprecation.behavior = old_behavior | ||
| 27 | end | ||
| 28 | end | ||
| 29 | |||
| 30 | # Wrap tests that use Mocha and skip if unavailable. | ||
| 31 | def uses_mocha(test_name) | ||
| 32 | require 'mocha' unless Object.const_defined?(:Mocha) | ||
| 33 | rescue LoadError => load_error | ||
| 34 | $stderr.puts "Skipping #{test_name} tests. `gem install mocha` and try again." | ||
| 35 | else | ||
| 36 | yield | ||
| 37 | end | ||
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 @@ | |||
| 1 | require 'lib/activerecord_test_connector' | ||
| 2 | |||
| 3 | class ActiveRecordTestCase < Test::Unit::TestCase | ||
| 4 | # Set our fixture path | ||
| 5 | if ActiveRecordTestConnector.able_to_connect | ||
| 6 | self.fixture_path = File.join(File.dirname(__FILE__), '..', 'fixtures') | ||
| 7 | self.use_transactional_fixtures = true | ||
| 8 | end | ||
| 9 | |||
| 10 | def self.fixtures(*args) | ||
| 11 | super if ActiveRecordTestConnector.connected | ||
| 12 | end | ||
| 13 | |||
| 14 | def run(*args) | ||
| 15 | super if ActiveRecordTestConnector.connected | ||
| 16 | end | ||
| 17 | |||
| 18 | # Default so Test::Unit::TestCase doesn't complain | ||
| 19 | def test_truth | ||
| 20 | end | ||
| 21 | |||
| 22 | protected | ||
| 23 | |||
| 24 | def assert_queries(num = 1) | ||
| 25 | $query_count = 0 | ||
| 26 | yield | ||
| 27 | ensure | ||
| 28 | assert_equal num, $query_count, "#{$query_count} instead of #{num} queries were executed." | ||
| 29 | end | ||
| 30 | |||
| 31 | def assert_no_queries(&block) | ||
| 32 | assert_queries(0, &block) | ||
| 33 | end | ||
| 34 | end | ||
| 35 | |||
| 36 | ActiveRecordTestConnector.setup | ||
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 @@ | |||
| 1 | require 'active_record' | ||
| 2 | require 'active_record/version' | ||
| 3 | require 'active_record/fixtures' | ||
| 4 | |||
| 5 | class ActiveRecordTestConnector | ||
| 6 | cattr_accessor :able_to_connect | ||
| 7 | cattr_accessor :connected | ||
| 8 | |||
| 9 | FIXTURES_PATH = File.join(File.dirname(__FILE__), '..', 'fixtures') | ||
| 10 | |||
| 11 | # Set our defaults | ||
| 12 | self.connected = false | ||
| 13 | self.able_to_connect = true | ||
| 14 | |||
| 15 | def self.setup | ||
| 16 | unless self.connected || !self.able_to_connect | ||
| 17 | setup_connection | ||
| 18 | load_schema | ||
| 19 | add_load_path FIXTURES_PATH | ||
| 20 | self.connected = true | ||
| 21 | end | ||
| 22 | rescue Exception => e # errors from ActiveRecord setup | ||
| 23 | $stderr.puts "\nSkipping ActiveRecord tests: #{e}\n\n" | ||
| 24 | self.able_to_connect = false | ||
| 25 | end | ||
| 26 | |||
| 27 | private | ||
| 28 | |||
| 29 | def self.add_load_path(path) | ||
| 30 | dep = defined?(ActiveSupport::Dependencies) ? ActiveSupport::Dependencies : ::Dependencies | ||
| 31 | dep.load_paths.unshift path | ||
| 32 | end | ||
| 33 | |||
| 34 | def self.setup_connection | ||
| 35 | db = ENV['DB'].blank?? 'sqlite3' : ENV['DB'] | ||
| 36 | |||
| 37 | configurations = YAML.load_file(File.join(File.dirname(__FILE__), '..', 'database.yml')) | ||
| 38 | raise "no configuration for '#{db}'" unless configurations.key? db | ||
| 39 | configuration = configurations[db] | ||
| 40 | |||
| 41 | ActiveRecord::Base.logger = Logger.new(STDOUT) if $0 == 'irb' | ||
| 42 | puts "using #{configuration['adapter']} adapter" unless ENV['DB'].blank? | ||
| 43 | |||
| 44 | 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 | ||
| 75 | end | ||
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 @@ | |||
| 1 | require 'boot' | ||
| 2 | require 'lib/activerecord_test_connector' | ||
| 3 | |||
| 4 | # setup the connection | ||
| 5 | ActiveRecordTestConnector.setup | ||
| 6 | |||
| 7 | # load all fixtures | ||
| 8 | Fixtures.create_fixtures(ActiveRecordTestConnector::FIXTURES_PATH, ActiveRecord::Base.connection.tables) | ||
| 9 | |||
| 10 | require 'will_paginate' | ||
| 11 | WillPaginate.enable_activerecord | ||
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 @@ | |||
| 1 | require 'action_controller' | ||
| 2 | require 'action_controller/test_process' | ||
| 3 | |||
| 4 | require 'will_paginate' | ||
| 5 | WillPaginate.enable_actionpack | ||
| 6 | |||
| 7 | ActionController::Routing::Routes.draw do |map| | ||
| 8 | map.connect 'dummy/page/:page', :controller => 'dummy' | ||
| 9 | map.connect 'dummy/dots/page.:page', :controller => 'dummy', :action => 'dots' | ||
| 10 | map.connect 'ibocorp/:page', :controller => 'ibocorp', | ||
| 11 | :requirements => { :page => /\d+/ }, | ||
| 12 | :defaults => { :page => 1 } | ||
| 13 | |||
| 14 | map.connect ':controller/:action/:id' | ||
| 15 | end | ||
| 16 | |||
| 17 | ActionController::Base.perform_caching = false | ||
| 18 | |||
| 19 | class WillPaginate::ViewTestCase < Test::Unit::TestCase | ||
| 20 | def setup | ||
| 21 | super | ||
| 22 | @controller = DummyController.new | ||
| 23 | @request = @controller.request | ||
| 24 | @html_result = nil | ||
| 25 | @template = '<%= will_paginate collection, options %>' | ||
| 26 | |||
| 27 | @view = ActionView::Base.new | ||
| 28 | @view.assigns['controller'] = @controller | ||
| 29 | @view.assigns['_request'] = @request | ||
| 30 | @view.assigns['_params'] = @request.params | ||
| 31 | end | ||
| 32 | |||
| 33 | def test_no_complain; end | ||
| 34 | |||
| 35 | protected | ||
| 36 | |||
| 37 | def paginate(collection = {}, options = {}, &block) | ||
| 38 | if collection.instance_of? Hash | ||
| 39 | page_options = { :page => 1, :total_entries => 11, :per_page => 4 }.merge(collection) | ||
| 40 | collection = [1].paginate(page_options) | ||
| 41 | end | ||
| 42 | |||
| 43 | locals = { :collection => collection, :options => options } | ||
| 44 | |||
| 45 | 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 | ||
| 106 | end | ||
| 107 | |||
| 108 | class 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 | ||
| 133 | end | ||
| 134 | |||
| 135 | class 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 | ||
| 151 | end | ||
| 152 | |||
| 153 | module 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 | ||
| 171 | end | ||
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 @@ | |||
| 1 | require 'rake/testtask' | ||
| 2 | |||
| 3 | desc 'Test the will_paginate plugin.' | ||
| 4 | Rake::TestTask.new(:test) do |t| | ||
| 5 | t.pattern = 'test/**/*_test.rb' | ||
| 6 | t.verbose = true | ||
| 7 | t.libs << 'test' | ||
| 8 | end | ||
| 9 | |||
| 10 | # I want to specify environment variables at call time | ||
| 11 | class 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 | ||
| 19 | end | ||
| 20 | |||
| 21 | for 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 | ||
| 28 | end | ||
| 29 | |||
| 30 | task :test_databases => %w(test_mysql test_sqlite3 test_postgres) | ||
| 31 | |||
| 32 | desc %{Test everything on SQLite3, MySQL and PostgreSQL} | ||
| 33 | task :test_full => %w(test test_mysql test_postgres) | ||
| 34 | |||
| 35 | desc %{Test everything with Rails 2.1.x, 2.0.x & 1.2.x gems} | ||
| 36 | task :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 | ||
| 44 | end | ||
| 45 | |||
| 46 | def 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 | ||
| 50 | end | ||
| 51 | |||
| 52 | task :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(',')}] | ||
| 59 | end | ||
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 @@ | |||
| 1 | require 'helper' | ||
| 2 | require 'lib/view_test_process' | ||
| 3 | |||
| 4 | class 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 | ||
| 13 | end | ||
| 14 | |||
| 15 | class 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 »" | ||
| 24 | end | ||
| 25 | assert_select 'span', 2 | ||
| 26 | assert_select 'span.disabled:first-child', '« Previous' | ||
| 27 | assert_select 'span.current', '1' | ||
| 28 | assert_equal '« Previous 1 2 3 Next »', 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">« 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 »</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('&').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', '« Previous' | ||
| 137 | assert_select elements.last, 'a', 'Next »' | ||
| 138 | end | ||
| 139 | assert_select 'span.current', '6' | ||
| 140 | assert_equal '« Previous 1 2 … 5 6 7 … 10 11 Next »', 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 - 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 - 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 - 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 | |||
| 365 | end | ||
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 @@ | |||
| 1 | Gem::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) | ||
| 20 | end | ||
