From 231f9640d82d725f252621d85761dc79dd49e421 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mislav=20Marohni=C4=87?= Date: Mon, 12 Jan 2009 05:40:52 +0100 Subject: [PATCH] Total rdoc love. Point out that this is framework-agnostic now --- CHANGELOG.rdoc | 21 ++--- LICENSE | 2 +- README.rdoc | 86 ++++++++++--------- Rakefile | 5 +- lib/will_paginate.rb | 4 +- lib/will_paginate/array.rb | 2 +- lib/will_paginate/collection.rb | 2 +- lib/will_paginate/finders/active_record.rb | 6 +- lib/will_paginate/finders/active_resource.rb | 9 +- lib/will_paginate/finders/base.rb | 13 ++- lib/will_paginate/finders/data_mapper.rb | 6 +- lib/will_paginate/view_helpers.rb | 31 ++++--- lib/will_paginate/view_helpers/action_view.rb | 25 +++++- lib/will_paginate/view_helpers/base.rb | 21 ++--- 14 files changed, 132 insertions(+), 101 deletions(-) diff --git a/CHANGELOG.rdoc b/CHANGELOG.rdoc index 829c0bbdd..fcb847a88 100644 --- a/CHANGELOG.rdoc +++ b/CHANGELOG.rdoc @@ -1,5 +1,13 @@ == "agnostic" branch +* added Sequel support +* added an initialization hook for Merb +* refactored URL generation +* BACKWARDS INCOMPATIBLE: refactored LinkRenderer; also markup changes + 1 is now 1 + a.prev_page -> a.previous_page (for consistency) +* "prev_label" -> "previous_label" +* ported view tests to specs * setup Autotest * added per_page=(limit) attribute writer to set default per_page * Remove :include option from count_all query when possible (Rails 2.1) @@ -7,19 +15,12 @@ * specs for ViewHelpers::Base and LinkRendererBase * created LinkRendererBase that implements windowed visible page numbers logic * created WP::ViewHelpers::Base abstract module that implements generic view helpers -* converted finder tests to specs +* ported finder tests to specs * added WP::Finders::DataMapper * added WP::Finders::ActiveRecord mixin for ActiveRecord::Base * created WP::Finders::Base abstract module that implements generic pagination logic * removed dependency to ActiveSupport -=== TODO: - -* Make a concrete implementation of LinkRendererBase that will generate HTML for both ActionView and Merb -* ActionView and Merb integration tests for view helpers -* 3c4725 Oops, I used return in an iterator block. I obviously write too much JavaScript -* 537f22 ensure that 'href' values in pagination links are escaped URLs - == 2.3.1, released 2008-05-04 * Fixed page numbers not showing with custom routes and implicit first page @@ -49,14 +50,14 @@ gem install mislav-will_paginate * extract reusable pagination testing stuff into WillPaginate::View -* rethink the page URL construction mechanizm to be more bulletproof when +* rethink the page URL construction mechanism to be more bulletproof when combined with custom routing for page parameter * test that anchor parameter can be used in pagination links == 2.2.2, released 2008-04-21 * Add support for page parameter in custom routes like "/foo/page/2" -* Change output of "page_entries_info" on single-page collection and erraneous +* Change output of "page_entries_info" on single-page collection and erroneous output with empty collection as reported by Tim Chater == 2.2.1, released 2008-04-08 diff --git a/LICENSE b/LICENSE index 96a48cb3f..44c52a6a0 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2007 PJ Hyett and Mislav Marohnić +Copyright (c) 2009 Mislav Marohnić Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in diff --git a/README.rdoc b/README.rdoc index a402a7ba0..3bb5307b7 100644 --- a/README.rdoc +++ b/README.rdoc @@ -1,7 +1,7 @@ -= WillPaginate += The will_paginate Ruby library -Pagination is just limiting the number of records displayed. Why should you let it get in your way -while developing? +Pagination is just limiting the number of records loaded and displayed. Why should you let it get in +your way while developing? This is how you paginate on an ActiveRecord model: @@ -11,30 +11,43 @@ Most of the time it's as simple as replacing "find" with "paginate" and specifyi Some resources to get you started: -* The {will_paginate project page}[http://github.com/mislav/will_paginate]; +* The {will_paginate project page}[http://mislav.github.com/will_paginate/]; * Your mind reels with questions? Join our {Google group}[http://groups.google.com/group/will_paginate]; * {How to report bugs}[http://github.com/mislav/will_paginate/wikis/report-bugs]; * {Watch the will_paginate screencast}[http://railscasts.com/episodes/51] by Ryan Bates. +== I'm not using Rails; can I still use will_paginate? + +Absolutely -- although will_paginate started off as a Rails plugin, now it is a completely +framework-agnostic library with support for Rails and Merb built-in. The core library doesn't +have any dependences and you can safely use it in any Ruby code. + +When will_paginate is loaded in an environment where ActiveRecord and ActionView are present, it +automatically hooks into these frameworks to provide easy pagination on your models and in your +views. The same mechanism works for Merb applications, too. But, if no known framework is present +then you have absolute control over what parts of will_paginate do you want to load and where you want +them mixed in. + == Installation -The recommended way is that you get the gem: +The recommended way is that you get the gem hosted on {gems.github.com}[http://gems.github.com/]: - gem install --source=http://gems.github.com/ mislav-will_paginate + gem install mislav-will_paginate -After that you don't need the will_paginate plugin in your Rails application anymore. In -Rails 2.1, add a gem dependency: +In Rails 2.1, add a gem dependency: - config.gem 'mislav-will_paginate', :lib => 'will_paginate', :version => '~> 2.5' + # for Rails 2.1 and newer + config.gem 'mislav-will_paginate', :lib => 'will_paginate', :version => '~> 3.0' -If you're using Rails 2.0 or older, just add a simple require to the end of your -"config/environment.rb" instead: +If you're using Rails 2.0 or older, or any other Ruby framework, just add a simple require to a file +that initializes your application. For example, in Rails you would put this at the end of +"config/environment.rb". - gem 'mislav-will_paginate', '~> 2.5' + gem 'mislav-will_paginate', '~> 3.0' require 'will_paginate' -That's it. Remember to install the gem on all machines that you are deploying to. +That's it. Remember to install the gem on all machines that you are deploying to. There are extensive {installation instructions}[http://github.com/mislav/will_paginate/wikis/installation] on {the @@ -43,40 +56,35 @@ wiki}[http://github.com/mislav/will_paginate/wikis]. == Example usage -Use a paginate finder in the controller: +Typical usage involves a paginating find in the controller: + + @posts = Post.paginate :page => params[:page], :order => 'updated_at DESC' - @posts = Post.paginate_by_board_id( - @board.id, - :page => params[:page], - :order => 'updated_at DESC' - ) +It's true: +paginate+ works just like +find+ -- it just doesn't fetch all the records. Don't forget +to tell it which page you want, or it will complain! Read more in WillPaginate::Finders. -Yeah, +paginate+ works just like +find+ -- it just doesn't fetch all the records. Don't forget to -tell it which page you want, or it will complain! Read more about WillPaginate::Finders. - -Render the posts in your view like you would normally do. When you need to render pagination, just -stick this in: +Render the posts in your view like you would normally do, and when you need to render pagination, +just stick this in: <%= will_paginate @posts %> -You're done. (Copy and paste the example fancy CSS styles from the bottom.) You can find the option -list at WillPaginate::ViewHelpers. +You're done. Read more in WillPaginate::ViewHelpers::Base. How does it know how much items to fetch per page? It asks your model by calling its -per_page class method. You can define it like this: ++per_page+ class method. You can define it like this: class Post < ActiveRecord::Base - def self.per_page() 50 end + self.per_page = 50 end -... or don't worry about it at all. WillPaginate defines it to be 30 by default. You can +... or don't worry about it at all. WillPaginate defines it to be 30 by default. You can always specify the count explicitly when calling +paginate+: - @posts = Post.paginate :page => params[:page], :per_page => 50 + Post.paginate :page => params[:page], :per_page => 50 The +paginate+ finder wraps the original finder and returns your result set that now has some new properties. You can use the collection as you would use any other array. WillPaginate view helpers -also need that object to be able to render pagination: +also need that collection object to be able to render pagination:
    <% for post in @posts -%> @@ -87,17 +95,11 @@ also need that object to be able to render pagination:

    Now let's render us some pagination!

    <%= will_paginate @posts %> -More detailed documentation: - -* WillPaginate::Finders for pagination on your models; -* WillPaginate::ViewHelpers for your views. - == Authors and credits -Authors:: Mislav Marohnić, PJ Hyett -Original announcement:: http://errtheblog.com/post/929 -Original PHP source:: http://www.strangerstudios.com/sandbox/pagination/diggstyle.php +The original author of will_paginate is PJ Hyett, who later handed over development to Mislav +Marohnić. The library was almost completely rewritten twice since then. All these people helped making will_paginate what it is now with their code contributions or just simply awesome ideas: @@ -105,13 +107,13 @@ simply awesome ideas: Chris Wanstrath, Dr. Nic Williams, K. Adam Christensen, Mike Garey, Bence Golda, Matt Aimonetti, Charles Brian Quinn, Desi McAdam, James Coglan, Matijs van Zuijlen, Maria, Brendan Ribera, Todd Willey, Bryan Helmkamp, Jan Berkel, Lourens Naudé, Rick Olson, Russell Norris, Piotr Usewicz, Chris -Eppstein. +Eppstein, Brandon Arbini, Denis Barushev, Paul Barry, Ben Pickles, Ken Collins, Lida Tang and Pieter +Noordhuis. == Usable pagination in the UI -There are some CSS styles to get you started in the "examples/" directory. They are showcased in the -"examples/index.html" file. +There are example CSS styles to get you started on the will_paginate project page. More reading about pagination as design pattern: diff --git a/Rakefile b/Rakefile index 683b0b9cb..7a9ed217c 100644 --- a/Rakefile +++ b/Rakefile @@ -16,8 +16,11 @@ desc 'Generate RDoc documentation for the will_paginate plugin.' Rake::RDocTask.new(:rdoc) do |rdoc| rdoc.rdoc_files.include('README.rdoc', 'LICENSE', 'CHANGELOG.rdoc'). include('lib/**/*.rb'). - exclude('lib/will_paginate/named_scope*'). + exclude('lib/will_paginate/finders/active_record/named_scope*'). + exclude('lib/will_paginate/finders/sequel.rb'). + exclude('lib/will_paginate/view_helpers/merb.rb'). exclude('lib/will_paginate/deprecation.rb'). + exclude('lib/will_paginate/core_ext.rb'). exclude('lib/will_paginate/version.rb') rdoc.main = "README.rdoc" # page to start on diff --git a/lib/will_paginate.rb b/lib/will_paginate.rb index 8fc4400e4..38ceb5043 100644 --- a/lib/will_paginate.rb +++ b/lib/will_paginate.rb @@ -2,12 +2,14 @@ # = You *will* paginate! # -# First read about WillPaginate::Finder::ClassMethods, then see +# First read about WillPaginate::Finders::Base, then see # WillPaginate::ViewHelpers. The magical array you're handling in-between is # WillPaginate::Collection. # # Happy paginating! module WillPaginate + # This method used to hook in ActiveRecord and ActionView at load time, + # but now doesn't do anything anymore and will be removed in future releases. def self.enable Deprecation.warn "WillPaginate::enable() doesn't do anything anymore" end diff --git a/lib/will_paginate/array.rb b/lib/will_paginate/array.rb index 10767600d..cd7f3ebca 100644 --- a/lib/will_paginate/array.rb +++ b/lib/will_paginate/array.rb @@ -2,7 +2,7 @@ class Array # Paginates a static array (extracting a subset of it). The result is a - # WillPaginate::Collection instance, which is an array with few more + # WillPaginate::Collection instance, which is an array with a few more # properties about its paginated state. # # Parameters: diff --git a/lib/will_paginate/collection.rb b/lib/will_paginate/collection.rb index 89d992f6f..c90629e49 100644 --- a/lib/will_paginate/collection.rb +++ b/lib/will_paginate/collection.rb @@ -17,7 +17,7 @@ module WillPaginate # requested. Use WillPaginate::Collection#out_of_bounds? method to # check for those cases and manually deal with them as you see fit. class InvalidPage < ArgumentError - def initialize(page, page_num) + def initialize(page, page_num) #:nodoc: super "#{page.inspect} given as value, which translates to '#{page_num}' as page number" end end diff --git a/lib/will_paginate/finders/active_record.rb b/lib/will_paginate/finders/active_record.rb index 84c99ffaf..62dfa347b 100644 --- a/lib/will_paginate/finders/active_record.rb +++ b/lib/will_paginate/finders/active_record.rb @@ -99,7 +99,7 @@ def method_missing_with_paginate(method, *args, &block) #:nodoc: paginate(*args, &block) end - def wp_query(options, pager, args, &block) + def wp_query(options, pager, args, &block) #:nodoc: finder = (options.delete(:finder) || 'find').to_s find_options = options.except(:count).update(:offset => pager.offset, :limit => pager.per_page) @@ -121,7 +121,7 @@ def wp_query(options, pager, args, &block) # Does the not-so-trivial job of finding out the total number of entries # in the database. It relies on the ActiveRecord +count+ method. - def wp_count(options, args, finder) + def wp_count(options, args, finder) #:nodoc: # find out if we are in a model or an association proxy klass = (@owner and @reflection) ? @reflection.klass : self count_options = wp_parse_count_options(options, klass) @@ -145,7 +145,7 @@ def wp_count(options, args, finder) count.respond_to?(:length) ? count.length : count end - def wp_parse_count_options(options, klass) + def wp_parse_count_options(options, klass) #:nodoc: excludees = [:count, :order, :limit, :offset, :readonly] unless ::ActiveRecord::Calculations::CALCULATIONS_OPTIONS.include?(:from) diff --git a/lib/will_paginate/finders/active_resource.rb b/lib/will_paginate/finders/active_resource.rb index 9ba0236bf..6333a3be4 100644 --- a/lib/will_paginate/finders/active_resource.rb +++ b/lib/will_paginate/finders/active_resource.rb @@ -4,13 +4,16 @@ module WillPaginate::Finders # Paginate your ActiveResource models. # - # @posts = Post.paginate :all, :params => { :page => params[:page], :order => 'created_at DESC' } + # @posts = Post.paginate :all, :params => { + # :page => params[:page], :order => 'created_at DESC' + # } + # module ActiveResource include WillPaginate::Finders::Base protected - def wp_query(options, pager, args, &block) + def wp_query(options, pager, args, &block) #:nodoc: unless args.empty? or args.first == :all raise ArgumentError, "finder arguments other than :all are not supported for pagination (#{args.inspect} given)" end @@ -26,7 +29,7 @@ def wp_query(options, pager, args, &block) # parses it into a WillPaginate::Collection, # and forwards the result to the former +instantiate_collection+ method. # It only does this for hashes that have a :type => "collection". - def instantiate_collection_with_collection(collection, prefix_options = {}) + def instantiate_collection_with_collection(collection, prefix_options = {}) #:nodoc: if collection.is_a?(Hash) && collection["type"] == "collection" collectables = collection.values.find{ |c| c.is_a?(Hash) || c.is_a?(Array) } collectables = [collectables].compact unless collectables.kind_of?(Array) diff --git a/lib/will_paginate/finders/base.rb b/lib/will_paginate/finders/base.rb index f64324406..3e39a1dd7 100644 --- a/lib/will_paginate/finders/base.rb +++ b/lib/will_paginate/finders/base.rb @@ -2,7 +2,18 @@ module WillPaginate module Finders - # Database-agnostic finder logic + # = Database-agnostic finder module + # + # Out of the box, will_paginate supports hooking in several ORMs to provide paginating + # finders based on their API. As of this writing, the supported libraries are: + # + # * ActiveRecord + # * DataMapper + # * Sequel + # + # It's easy to write your own adapter for anything that can load data with explicit + # limit and offset settings. DataMapper adapter is a nice and compact example of + # writing an adapter to bring the +paginate+ method to DataMapper models. module Base def per_page @per_page ||= 30 diff --git a/lib/will_paginate/finders/data_mapper.rb b/lib/will_paginate/finders/data_mapper.rb index c31c5fb7f..20d68e926 100644 --- a/lib/will_paginate/finders/data_mapper.rb +++ b/lib/will_paginate/finders/data_mapper.rb @@ -5,9 +5,9 @@ module WillPaginate::Finders module DataMapper include WillPaginate::Finders::Base - protected + protected - def wp_query(options, pager, args, &block) + def wp_query(options, pager, args, &block) #:nodoc find_options = options.except(:count).update(:offset => pager.offset, :limit => pager.per_page) pager.replace all(find_options, &block) @@ -17,7 +17,7 @@ def wp_query(options, pager, args, &block) end end - def wp_count(options) + def wp_count(options) #:nodoc count_options = options.except(:count, :order) # merge the hash found in :count count_options.update options[:count] if options[:count] diff --git a/lib/will_paginate/view_helpers.rb b/lib/will_paginate/view_helpers.rb index 9917cc5e5..ecb3076f6 100644 --- a/lib/will_paginate/view_helpers.rb +++ b/lib/will_paginate/view_helpers.rb @@ -3,23 +3,26 @@ module WillPaginate # = Will Paginate view helpers # - # Currently there is only one view helper: +will_paginate+. It renders the - # pagination links for the given collection. The helper itself is lightweight - # and serves only as a wrapper around link renderer instantiation; the - # renderer then does all the hard work of generating the HTML. + # The main view helper is +will_paginate+. It renders the pagination links + # for the given collection. The helper itself is lightweight and serves only + # as a wrapper around LinkRenderer instantiation; the renderer then does + # all the hard work of generating the HTML. # - # == Global options for helpers - # - # Options for pagination helpers are optional and get their default values from the - # WillPaginate::ViewHelpers.pagination_options hash. You can write to this hash to - # override default options on the global level: - # - # WillPaginate::ViewHelpers.pagination_options[:previous_label] = 'Previous page' - # - # By putting this into your environment.rb you can easily translate link texts to previous - # and next pages, as well as override some other defaults to your liking. + # Read more in WillPaginate::ViewHelpers::Base module ViewHelpers + # ==== Global options for helpers + # + # Options for pagination helpers are optional and get their default values + # from the WillPaginate::ViewHelpers.pagination_options hash. You can write + # to this hash to override default options on the global level: + # + # WillPaginate::ViewHelpers.pagination_options[:previous_label] = 'Previous page' + # + # By putting this into your environment.rb you can easily translate link + # texts to previous and next pages, as well as override some other defaults + # to your liking. def self.pagination_options() @pagination_options; end + # Overrides the default +pagination_options+ def self.pagination_options=(value) @pagination_options = value; end self.pagination_options = { diff --git a/lib/will_paginate/view_helpers/action_view.rb b/lib/will_paginate/view_helpers/action_view.rb index 49fe68809..6c9dc245c 100644 --- a/lib/will_paginate/view_helpers/action_view.rb +++ b/lib/will_paginate/view_helpers/action_view.rb @@ -5,18 +5,35 @@ module WillPaginate module ViewHelpers - # ActionView helpers for Rails integration + # = ActionView helpers + # + # This module serves for availability in ActionView templates. It also adds a new + # view helper: +paginated_section+. + # + # == Using the helper without arguments + # If the helper is called without passing in the collection object, it will + # try to read from the instance variable inferred by the controller name. + # For example, calling +will_paginate+ while the current controller is + # PostsController will result in trying to read from the @posts + # variable. Example: + # + # <%= will_paginate :id => true %> + # + # ... will result in @post collection getting paginated: + # + # + # module ActionView include WillPaginate::ViewHelpers::Base - def will_paginate(collection = nil, options = {}) + def will_paginate(collection = nil, options = {}) #:nodoc: options, collection = collection, nil if collection.is_a? Hash collection ||= infer_collection_from_controller super(collection, options.symbolize_keys) end - def page_entries_info(collection = nil, options = {}) + def page_entries_info(collection = nil, options = {}) #:nodoc: options, collection = collection, nil if collection.is_a? Hash collection ||= infer_collection_from_controller @@ -72,7 +89,7 @@ def infer_collection_from_controller end ActionView::Base.send :include, WillPaginate::ViewHelpers::ActionView - +# :stopdoc: if defined?(ActionController::Base) and ActionController::Base.respond_to? :rescue_responses ActionController::Base.rescue_responses['WillPaginate::InvalidPage'] = :not_found end diff --git a/lib/will_paginate/view_helpers/base.rb b/lib/will_paginate/view_helpers/base.rb index c5a0ecba9..73c8375e8 100644 --- a/lib/will_paginate/view_helpers/base.rb +++ b/lib/will_paginate/view_helpers/base.rb @@ -3,10 +3,12 @@ module WillPaginate module ViewHelpers + # = The main view helpers module + # + # This is the base module which provides the +will_paginate+ view helper. module Base - # Renders Digg/Flickr-style pagination for a WillPaginate::Collection - # object. Nil is returned if there is only one page in total; no point in - # rendering the pagination in that case... + # Renders Digg/Flickr-style pagination for a WillPaginate::Collection object. Nil is + # returned if there is only one page in total; pagination links aren't needed in that case. # # ==== Options # * :class -- CSS class name for the generated DIV (default: "pagination") @@ -36,19 +38,6 @@ module Base # # # - # ==== Using the helper without arguments - # If the helper is called without passing in the collection object, it will - # try to read from the instance variable inferred by the controller name. - # For example, calling +will_paginate+ while the current controller is - # PostsController will result in trying to read from the @posts - # variable. Example: - # - # <%= will_paginate :id => true %> - # - # ... will result in @post collection getting paginated: - # - # - # def will_paginate(collection, options = {}) # early exit if there is nothing to render return nil unless collection.total_pages > 1