Replace will_paginate plugin by gem and upgrade to 2.3.16

master
Alinson S. Xavier 12 years ago
parent 7a8e3ec065
commit 9a22c8eaf5

@ -79,5 +79,6 @@ Rails::Initializer.run do |config|
config.gem "haml" config.gem "haml"
config.gem "hpricot" config.gem "hpricot"
config.gem "icalendar" config.gem "icalendar"
config.gem "will_paginate"
config.gem 'thoughtbot-shoulda', :lib => 'shoulda/rails', :source => "http://gems.github.com" config.gem 'thoughtbot-shoulda', :lib => 'shoulda/rails', :source => "http://gems.github.com"
end end

@ -23,6 +23,7 @@ hpricot (0.6)
i18n (0.6.4) i18n (0.6.4)
icalendar (1.0) icalendar (1.0)
json_pure (1.8.0) json_pure (1.8.0)
magic_encoding (0.0.2)
minitest (4.7.5) minitest (4.7.5)
multi_json (1.7.7) multi_json (1.7.7)
quietbacktrace (0.1.1) quietbacktrace (0.1.1)
@ -36,4 +37,5 @@ rvm (1.11.3.8)
sqlite3-ruby (1.3.1) sqlite3-ruby (1.3.1)
thread_safe (0.1.0) thread_safe (0.1.0)
tzinfo (0.3.37) tzinfo (0.3.37)
will_paginate (2.3.16)
ZenTest (3.11.1) ZenTest (3.11.1)

@ -1,18 +0,0 @@
Copyright (c) 2007 PJ Hyett and 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
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

@ -1,171 +0,0 @@
= WillPaginate
Pagination is just limiting the number of records displayed. Why should you let
it get in your way while developing, then? This plugin makes magic happen. Did
you ever want to be able to do just this on a model:
Post.paginate :page => 1, :order => 'created_at DESC'
... and then render the page links with a single view helper? Well, now you
can.
Ryan Bates made an awesome screencast[http://railscasts.com/episodes/51],
check it out.
Your mind reels with questions? Join our Google
group[http://groups.google.com/group/will_paginate].
== Install the plugin
Simply do:
script/plugin install svn://errtheblog.com/svn/plugins/will_paginate
Alternatively, you can add the whole Err repository to plugin sources:
script/plugin source svn://errtheblog.com/svn/plugins
You only have to do this once, then you can install will_paginate to each of your applications simply like this:
script/plugin install will_paginate
To see what other plugins are now available to you, list the newly added plugin source:
script/plugin list --source=svn://errtheblog.com/svn/plugins
The plugin officially supports Rails versions 1.2.6 and 2.0.2. You can browse
its source code on Warehouse: http://plugins.require.errtheblog.com/browser/will_paginate
== Example usage
Use a paginate finder in the controller:
@posts = Post.paginate_by_board_id @board.id, :page => params[:page], :order => 'updated_at DESC'
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 on WillPaginate::Finder::ClassMethods.
Render the posts in your view like you would normally do. 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.
How does it know how much items to fetch per page? It asks your model by calling
its <tt>per_page</tt> class method. You can define it like this:
class Post < ActiveRecord::Base
cattr_reader :per_page
@@per_page = 50
end
... or like this:
class Post < ActiveRecord::Base
def self.per_page
50
end
end
... or don't worry about it at all. WillPaginate defines it to be <b>30</b> by default.
But you can always specify the count explicitly when calling +paginate+:
@posts = Post.paginate :page => params[:page], :per_page => 50
The +paginate+ finder wraps the original finder and returns your resultset that now has
some new properties. You can use the collection as you would with any ActiveRecord
resultset. WillPaginate view helpers also need that object to be able to render pagination:
<ol>
<% for post in @posts -%>
<li>Render `post` in some nice way.</li>
<% end -%>
</ol>
<p>Now let's render us some pagination!</p>
<%= will_paginate @posts %>
More detailed documentation:
* WillPaginate::Finder::ClassMethods for pagination on your models;
* WillPaginate::ViewHelpers for your views.
== Oh noes, a bug!
Tell us what happened so we can fix it, quick! Issues are filed on the Lighthouse project:
http://err.lighthouseapp.com/projects/466-plugins/tickets?q=tagged:will_paginate
Steps to make an awesome bug report:
1. Run <tt>rake test</tt> in the <i>will_paginate</i> directory. (You will need SQLite3.)
Copy the output if there are failing tests.
2. Register on Lighthouse to create a new ticket.
3. Write a descriptive, short title. Provide as much info as you can in the body.
Assign the ticket to Mislav and tag it with meaningful tags, <tt>"will_paginate"</tt>
being among them.
4. Yay! You will be notified on updates automatically.
Here is an example of a great bug report and patch:
http://err.lighthouseapp.com/projects/466/tickets/172-total_entries-ignored-in-paginate_by_sql
== Authors, credits, contact
Want to discuss, request features, ask questions? Join the Google group:
http://groups.google.com/group/will_paginate
Authors:: Mislav Marohnić, PJ Hyett
Original announcement:: http://errtheblog.com/post/929
Original PHP source:: http://www.strangerstudios.com/sandbox/pagination/diggstyle.php
All these people helped making will_paginate what it is now with their code
contributions or 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.
== Usable pagination in the UI
Copy the following CSS into your stylesheet for a good start:
.pagination {
padding: 3px;
margin: 3px;
}
.pagination a {
padding: 2px 5px 2px 5px;
margin: 2px;
border: 1px solid #aaaadd;
text-decoration: none;
color: #000099;
}
.pagination a:hover, .pagination a:active {
border: 1px solid #000099;
color: #000;
}
.pagination span.current {
padding: 2px 5px 2px 5px;
margin: 2px;
border: 1px solid #000099;
font-weight: bold;
background-color: #000099;
color: #FFF;
}
.pagination span.disabled {
padding: 2px 5px 2px 5px;
margin: 2px;
border: 1px solid #eee;
color: #ddd;
}
More reading about pagination as design pattern:
* Pagination 101:
http://kurafire.net/log/archive/2007/06/22/pagination-101
* Pagination gallery:
http://www.smashingmagazine.com/2007/11/16/pagination-gallery-examples-and-good-practices/
* Pagination on Yahoo Design Pattern Library:
http://developer.yahoo.com/ypatterns/parent.php?pattern=pagination

@ -1,65 +0,0 @@
require 'rake'
require 'rake/testtask'
require 'rake/rdoctask'
desc 'Default: run unit tests.'
task :default => :test
desc 'Test the will_paginate plugin.'
Rake::TestTask.new(:test) do |t|
t.pattern = 'test/**/*_test.rb'
t.verbose = true
end
# I want to specify environment variables at call time
class EnvTestTask < Rake::TestTask
attr_accessor :env
def ruby(*args)
env.each { |key, value| ENV[key] = value } if env
super
env.keys.each { |key| ENV.delete key } if env
end
end
for configuration in %w( sqlite3 mysql postgres )
EnvTestTask.new("test_#{configuration}") do |t|
t.pattern = 'test/finder_test.rb'
t.verbose = true
t.env = { 'DB' => configuration }
end
end
task :test_databases => %w(test_mysql test_sqlite3 test_postgres)
desc %{Test everything on SQLite3, MySQL and PostgreSQL}
task :test_full => %w(test test_mysql test_postgres)
desc %{Test everything with Rails 1.2.x and 2.0.x gems}
task :test_all do
all = Rake::Task['test_full']
ENV['RAILS_VERSION'] = '~>1.2.6'
all.invoke
# reset the invoked flag
%w( test_full test test_mysql test_postgres ).each do |name|
Rake::Task[name].instance_variable_set '@already_invoked', false
end
# do it again
ENV['RAILS_VERSION'] = '~>2.0.2'
all.invoke
end
desc 'Generate RDoc documentation for the will_paginate plugin.'
Rake::RDocTask.new(:rdoc) do |rdoc|
files = ['README', 'LICENSE', 'lib/**/*.rb']
rdoc.rdoc_files.add(files)
rdoc.main = "README" # page to start on
rdoc.title = "will_paginate"
templates = %w[/Users/chris/ruby/projects/err/rock/template.rb /var/www/rock/template.rb]
rdoc.template = templates.find { |t| File.exists? t }
rdoc.rdoc_dir = 'doc' # rdoc output folder
rdoc.options << '--inline-source'
rdoc.options << '--charset=UTF-8'
end

@ -1,2 +0,0 @@
require 'will_paginate'
WillPaginate.enable

@ -1,61 +0,0 @@
require 'active_support'
# = You *will* paginate!
#
# First read about WillPaginate::Finder::ClassMethods, then see
# WillPaginate::ViewHelpers. The magical array you're handling in-between is
# WillPaginate::Collection.
#
# Happy paginating!
module WillPaginate
class << self
# shortcut for <tt>enable_actionpack; enable_activerecord</tt>
def enable
enable_actionpack
enable_activerecord
end
# mixes in WillPaginate::ViewHelpers in ActionView::Base
def enable_actionpack
return if ActionView::Base.instance_methods.include? 'will_paginate'
require 'will_paginate/view_helpers'
ActionView::Base.class_eval { include ViewHelpers }
end
# mixes in WillPaginate::Finder in ActiveRecord::Base and classes that deal
# with associations
def enable_activerecord
return if ActiveRecord::Base.respond_to? :paginate
require 'will_paginate/finder'
ActiveRecord::Base.class_eval { include Finder }
associations = ActiveRecord::Associations
collection = associations::AssociationCollection
# to support paginating finders on associations, we have to mix in the
# method_missing magic from WillPaginate::Finder::ClassMethods to AssociationProxy
# subclasses, but in a different way for Rails 1.2.x and 2.0
(collection.instance_methods.include?(:create!) ?
collection : collection.subclasses.map(&:constantize)
).push(associations::HasManyThroughAssociation).each do |klass|
klass.class_eval do
include Finder::ClassMethods
alias_method_chain :method_missing, :paginate
end
end
end
end
module Deprecation #:nodoc:
extend ActiveSupport::Deprecation
def self.warn(message, callstack = caller)
message = 'WillPaginate: ' + message.strip.gsub(/ {3,}/, ' ')
behavior.call(message, callstack) if behavior && !silenced?
end
def self.silenced?
ActiveSupport::Deprecation.silenced?
end
end
end

@ -1,132 +0,0 @@
require 'will_paginate'
module WillPaginate
# = OMG, invalid page number!
# This is an ArgumentError raised in case a page was requested that is either
# zero or negative number. You should decide how do deal with such errors in
# the controller.
#
# This error is *not* raised when a page further than the last page is
# requested. Use <tt>WillPaginate::Collection#out_of_bounds?</tt> method to
# check for those cases and manually deal with them as you see fit.
class InvalidPage < ArgumentError
def initialize(page, page_num)
super "#{page.inspect} given as value, which translates to '#{page_num}' as page number"
end
end
# Arrays returned from paginating finds are, in fact, instances of this.
# You may think of WillPaginate::Collection as an ordinary array with some
# extra properties. Those properties are used by view helpers to generate
# correct page links.
#
# WillPaginate::Collection also assists in rolling out your own pagination
# solutions: see +create+.
#
class Collection < Array
attr_reader :current_page, :per_page, :total_entries
# Arguments to this constructor are the current page number, per-page limit
# and the total number of entries. The last argument is optional because it
# is best to do lazy counting; in other words, count *conditionally* after
# populating the collection using the +replace+ method.
#
def initialize(page, per_page, total = nil)
@current_page = page.to_i
raise InvalidPage.new(page, @current_page) if @current_page < 1
@per_page = per_page.to_i
raise ArgumentError, "`per_page` setting cannot be less than 1 (#{@per_page} given)" if @per_page < 1
self.total_entries = total if total
end
# Just like +new+, but yields the object after instantiation and returns it
# afterwards. This is very useful for manual pagination:
#
# @entries = WillPaginate::Collection.create(1, 10) do |pager|
# result = Post.find(:all, :limit => pager.per_page, :offset => pager.offset)
# # inject the result array into the paginated collection:
# pager.replace(result)
#
# unless pager.total_entries
# # the pager didn't manage to guess the total count, do it manually
# pager.total_entries = Post.count
# end
# end
#
# The possibilities with this are endless. For another example, here is how
# WillPaginate used to define pagination for Array instances:
#
# Array.class_eval do
# def paginate(page = 1, per_page = 15)
# WillPaginate::Collection.create(page, per_page, size) do |pager|
# pager.replace self[pager.offset, pager.per_page].to_a
# end
# end
# end
#
def self.create(page, per_page, total = nil, &block)
pager = new(page, per_page, total)
yield pager
pager
end
# The total number of pages.
def page_count
@total_pages
end
# Helper method that is true when someone tries to fetch a page with a
# larger number than the last page. Can be used in combination with flashes
# and redirecting.
def out_of_bounds?
current_page > page_count
end
# Current offset of the paginated collection. If we're on the first page,
# it is always 0. If we're on the 2nd page and there are 30 entries per page,
# the offset is 30. This property is useful if you want to render ordinals
# besides your records: simply start with offset + 1.
#
def offset
(current_page - 1) * per_page
end
# current_page - 1 or nil if there is no previous page
def previous_page
current_page > 1 ? (current_page - 1) : nil
end
# current_page + 1 or nil if there is no next page
def next_page
current_page < page_count ? (current_page + 1) : nil
end
def total_entries=(number)
@total_entries = number.to_i
@total_pages = (@total_entries / per_page.to_f).ceil
end
# This is a magic wrapper for the original Array#replace method. It serves
# for populating the paginated collection after initialization.
#
# Why magic? Because it tries to guess the total number of entries judging
# by the size of given array. If it is shorter than +per_page+ limit, then we
# know we're on the last page. This trick is very useful for avoiding
# unnecessary hits to the database to do the counting after we fetched the
# data for the current page.
#
# However, after using +replace+ you should always test the value of
# +total_entries+ and set it to a proper value if it's +nil+. See the example
# in +create+.
def replace(array)
returning super do
# The collection is shorter then page limit? Rejoice, because
# then we know that we are on the last page!
if total_entries.nil? and length > 0 and length < per_page
self.total_entries = offset + length
end
end
end
end
end

@ -1,80 +0,0 @@
require 'will_paginate'
require 'set'
unless Hash.instance_methods.include? 'except'
Hash.class_eval do
# Returns a new hash without the given keys.
def except(*keys)
rejected = Set.new(respond_to?(:convert_key) ? keys.map { |key| convert_key(key) } : keys)
reject { |key,| rejected.include?(key) }
end
# Replaces the hash without only the given keys.
def except!(*keys)
replace(except(*keys))
end
end
end
unless Hash.instance_methods.include? 'slice'
Hash.class_eval do
# Returns a new hash with only the given keys.
def slice(*keys)
allowed = Set.new(respond_to?(:convert_key) ? keys.map { |key| convert_key(key) } : keys)
reject { |key,| !allowed.include?(key) }
end
# Replaces the hash with only the given keys.
def slice!(*keys)
replace(slice(*keys))
end
end
end
unless Hash.instance_methods.include? 'rec_merge!'
Hash.class_eval do
# Same as Hash#merge!, but recursively merges sub-hashes
# (stolen from Haml)
def rec_merge!(other)
other.each do |key, other_value|
value = self[key]
if value.is_a?(Hash) and other_value.is_a?(Hash)
value.rec_merge! other_value
else
self[key] = other_value
end
end
self
end
end
end
require 'will_paginate/collection'
unless Array.instance_methods.include? 'paginate'
# http://www.desimcadam.com/archives/8
Array.class_eval do
def paginate(options_or_page = {}, per_page = nil)
if options_or_page.nil? or Fixnum === options_or_page
if defined? WillPaginate::Deprecation
WillPaginate::Deprecation.warn <<-DEPR
Array#paginate now conforms to the main, ActiveRecord::Base#paginate API. You should \
call it with a parameters hash (:page, :per_page). The old API (numbers as arguments) \
has been deprecated and is going to be unsupported in future versions of will_paginate.
DEPR
end
page = options_or_page
options = {}
else
options = options_or_page
page = options[:page]
raise ArgumentError, "wrong number of arguments (1 hash or 2 Fixnums expected)" if per_page
per_page = options[:per_page]
end
WillPaginate::Collection.create(page || 1, per_page || 30, options[:total_entries] || size) do |pager|
pager.replace self[pager.offset, pager.per_page].to_a
end
end
end
end

@ -1,214 +0,0 @@
require 'will_paginate/core_ext'
module WillPaginate
# A mixin for ActiveRecord::Base. Provides +per_page+ class method
# and makes +paginate+ finders possible with some method_missing magic.
#
# Find out more in WillPaginate::Finder::ClassMethods
#
module Finder
def self.included(base)
base.extend ClassMethods
class << base
alias_method_chain :method_missing, :paginate
# alias_method_chain :find_every, :paginate
define_method(:per_page) { 30 } unless respond_to?(:per_page)
end
end
# = Paginating finders for ActiveRecord models
#
# WillPaginate adds +paginate+ and +per_page+ methods to ActiveRecord::Base
# class methods and associations. It also hooks into +method_missing+ to
# intercept pagination calls to dynamic finders such as
# +paginate_by_user_id+ and translate them to ordinary finders
# (+find_all_by_user_id+ in this case).
#
# In short, paginating finders are equivalent to ActiveRecord finders; the
# only difference is that we start with "paginate" instead of "find" and
# that <tt>:page</tt> is required parameter:
#
# @posts = Post.paginate :all, :page => params[:page], :order => 'created_at DESC'
#
# In paginating finders, "all" is implicit. There is no sense in paginating
# a single record, right? So, you can drop the <tt>:all</tt> argument:
#
# Post.paginate(...) => Post.find :all
# Post.paginate_all_by_something => Post.find_all_by_something
# Post.paginate_by_something => Post.find_all_by_something
#
# == The importance of the <tt>:order</tt> parameter
#
# In ActiveRecord finders, <tt>:order</tt> parameter specifies columns for
# the <tt>ORDER BY</tt> clause in SQL. It is important to have it, since
# pagination only makes sense with ordered sets. Without the <tt>ORDER
# BY</tt> clause, databases aren't required to do consistent ordering when
# performing <tt>SELECT</tt> queries; this is especially true for
# PostgreSQL.
#
# Therefore, make sure you are doing ordering on a column that makes the
# most sense in the current context. Make that obvious to the user, also.
# For perfomance reasons you will also want to add an index to that column.
module ClassMethods
# This is the main paginating finder.
#
# == Special parameters for paginating finders
# * <tt>:page</tt> -- REQUIRED, but defaults to 1 if false or nil
# * <tt>:per_page</tt> -- defaults to <tt>CurrentModel.per_page</tt> (which is 30 if not overridden)
# * <tt>:total_entries</tt> -- use only if you manually count total entries
# * <tt>:count</tt> -- additional options that are passed on to +count+
# * <tt>:finder</tt> -- name of the ActiveRecord finder used (default: "find")
#
# All other options (+conditions+, +order+, ...) are forwarded to +find+
# and +count+ calls.
def paginate(*args, &block)
options = args.pop
page, per_page, total_entries = wp_parse_options(options)
finder = (options[:finder] || 'find').to_s
if finder == 'find'
# an array of IDs may have been given:
total_entries ||= (Array === args.first and args.first.size)
# :all is implicit
args.unshift(:all) if args.empty?
end
WillPaginate::Collection.create(page, per_page, total_entries) do |pager|
count_options = options.except :page, :per_page, :total_entries, :finder
find_options = count_options.except(:count).update(:offset => pager.offset, :limit => pager.per_page)
args << find_options
# @options_from_last_find = nil
pager.replace send(finder, *args, &block)
# magic counting for user convenience:
pager.total_entries = wp_count(count_options, args, finder) unless pager.total_entries
end
end
# Wraps +find_by_sql+ by simply adding LIMIT and OFFSET to your SQL string
# based on the params otherwise used by paginating finds: +page+ and
# +per_page+.
#
# Example:
#
# @developers = Developer.paginate_by_sql ['select * from developers where salary > ?', 80000],
# :page => params[:page], :per_page => 3
#
# A query for counting rows will automatically be generated if you don't
# supply <tt>:total_entries</tt>. If you experience problems with this
# generated SQL, you might want to perform the count manually in your
# application.
#
def paginate_by_sql(sql, options)
WillPaginate::Collection.create(*wp_parse_options(options)) do |pager|
query = sanitize_sql(sql)
original_query = query.dup
# add limit, offset
add_limit! query, :offset => pager.offset, :limit => pager.per_page
# perfom the find
pager.replace find_by_sql(query)
unless pager.total_entries
count_query = original_query.sub /\bORDER\s+BY\s+[\w`,\s]+$/mi, ''
count_query = "SELECT COUNT(*) FROM (#{count_query})"
unless ['oracle', 'oci'].include?(self.connection.adapter_name.downcase)
count_query << ' AS count_table'
end
# perform the count query
pager.total_entries = count_by_sql(count_query)
end
end
end
def respond_to?(method, include_priv = false) #:nodoc:
case method.to_sym
when :paginate, :paginate_by_sql
true
else
super(method.to_s.sub(/^paginate/, 'find'), include_priv)
end
end
protected
def method_missing_with_paginate(method, *args, &block) #:nodoc:
# did somebody tried to paginate? if not, let them be
unless method.to_s.index('paginate') == 0
return method_missing_without_paginate(method, *args, &block)
end
# paginate finders are really just find_* with limit and offset
finder = method.to_s.sub('paginate', 'find')
finder.sub!('find', 'find_all') if finder.index('find_by_') == 0
options = args.pop
raise ArgumentError, 'parameter hash expected' unless options.respond_to? :symbolize_keys
options = options.dup
options[:finder] = finder
args << options
paginate(*args, &block)
end
# 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)
excludees = [:count, :order, :limit, :offset, :readonly]
unless options[:select] and options[:select] =~ /^\s*DISTINCT\b/i
excludees << :select # only exclude the select param if it doesn't begin with DISTINCT
end
# count expects (almost) the same options as find
count_options = options.except *excludees
# merge the hash found in :count
# this allows you to specify :select, :order, or anything else just for the count query
count_options.update options[:count] if options[:count]
# we may have to scope ...
counter = Proc.new { count(count_options) }
# we may be in a model or an association proxy!
klass = (@owner and @reflection) ? @reflection.klass : self
count = if finder.index('find_') == 0 and klass.respond_to?(scoper = finder.sub('find', 'with'))
# scope_out adds a 'with_finder' method which acts like with_scope, if it's present
# then execute the count with the scoping provided by the with_finder
send(scoper, &counter)
elsif match = /^find_(all_by|by)_([_a-zA-Z]\w*)$/.match(finder)
# extract conditions from calls like "paginate_by_foo_and_bar"
attribute_names = extract_attribute_names_from_match(match)
conditions = construct_attributes_from_arguments(attribute_names, args)
with_scope(:find => { :conditions => conditions }, &counter)
else
counter.call
end
count.respond_to?(:length) ? count.length : count
end
def wp_parse_options(options) #:nodoc:
raise ArgumentError, 'parameter hash expected' unless options.respond_to? :symbolize_keys
options = options.symbolize_keys
raise ArgumentError, ':page parameter required' unless options.key? :page
if options[:count] and options[:total_entries]
raise ArgumentError, ':count and :total_entries are mutually exclusive'
end
page = options[:page] || 1
per_page = options[:per_page] || self.per_page
total = options[:total_entries]
[page, per_page, total]
end
private
# def find_every_with_paginate(options)
# @options_from_last_find = options
# find_every_without_paginate(options)
# end
end
end
end

@ -1,206 +0,0 @@
require 'will_paginate/core_ext'
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.
#
# == 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[:prev_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.
module ViewHelpers
# default options that can be overridden on the global level
@@pagination_options = {
:class => 'pagination',
:prev_label => '&laquo; Previous',
:next_label => 'Next &raquo;',
:inner_window => 4, # links around the current page
:outer_window => 1, # links around beginning and end
:separator => ' ', # single space is friendly to spiders and non-graphic browsers
:param_name => :page,
:params => nil,
:renderer => 'WillPaginate::LinkRenderer',
:page_links => true,
:container => true
}
mattr_reader :pagination_options
# 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...
#
# ==== Options
# * <tt>:class</tt> -- CSS class name for the generated DIV (default: "pagination")
# * <tt>:prev_label</tt> -- default: "« Previous"
# * <tt>:next_label</tt> -- default: "Next »"
# * <tt>:inner_window</tt> -- how many links are shown around the current page (default: 4)
# * <tt>:outer_window</tt> -- how many links are around the first and the last page (default: 1)
# * <tt>:separator</tt> -- string separator for page HTML elements (default: single space)
# * <tt>:param_name</tt> -- parameter name for page number in URLs (default: <tt>:page</tt>)
# * <tt>:params</tt> -- additional parameters when generating pagination links
# (eg. <tt>:controller => "foo", :action => nil</tt>)
# * <tt>:renderer</tt> -- class name of the link renderer (default: WillPaginate::LinkRenderer)
# * <tt>:page_links</tt> -- when false, only previous/next links are rendered (default: true)
# * <tt>:container</tt> -- toggles rendering of the DIV container for pagination links, set to
# false only when you are rendering your own pagination markup (default: true)
# * <tt>:id</tt> -- HTML ID for the container (default: nil). Pass +true+ to have the ID automatically
# generated from the class name of objects in collection: for example, paginating
# ArticleComment models would yield an ID of "article_comments_pagination".
#
# All options beside listed ones are passed as HTML attributes to the container
# element for pagination links (the DIV). For example:
#
# <%= will_paginate @posts, :id => 'wp_posts' %>
#
# ... will result in:
#
# <div class="pagination" id="wp_posts"> ... </div>
#
# ==== 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 <tt>@posts</tt>
# variable. Example:
#
# <%= will_paginate :id => true %>
#
# ... will result in <tt>@post</tt> collection getting paginated:
#
# <div class="pagination" id="posts_pagination"> ... </div>
#
def will_paginate(collection = nil, options = {})
options, collection = collection, nil if collection.is_a? Hash
unless collection or !controller
collection_name = "@#{controller.controller_name}"
collection = instance_variable_get(collection_name)
raise ArgumentError, "The #{collection_name} variable appears to be empty. Did you " +
"forget to specify the collection object for will_paginate?" unless collection
end
# early exit if there is nothing to render
return nil unless collection.page_count > 1
options = options.symbolize_keys.reverse_merge WillPaginate::ViewHelpers.pagination_options
# create the renderer instance
renderer_class = options[:renderer].to_s.constantize
renderer = renderer_class.new collection, options, self
# render HTML for pagination
renderer.to_html
end
end
# This class does the heavy lifting of actually building the pagination
# links. It is used by +will_paginate+ helper internally, but avoid using it
# directly (for now) because its API is not set in stone yet.
class LinkRenderer
def initialize(collection, options, template)
@collection = collection
@options = options
@template = template
end
def to_html
links = @options[:page_links] ? windowed_links : []
# previous/next buttons
links.unshift page_link_or_span(@collection.previous_page, 'disabled', @options[:prev_label])
links.push page_link_or_span(@collection.next_page, 'disabled', @options[:next_label])
html = links.join(@options[:separator])
@options[:container] ? @template.content_tag(:div, html, html_attributes) : html
end
def html_attributes
return @html_attributes if @html_attributes
@html_attributes = @options.except *(WillPaginate::ViewHelpers.pagination_options.keys - [:class])
# pagination of Post models will have the ID of "posts_pagination"
if @options[:container] and @options[:id] === true
@html_attributes[:id] = @collection.first.class.name.underscore.pluralize + '_pagination'
end
@html_attributes
end
protected
def gap_marker; '...'; end
def windowed_links
prev = nil
visible_page_numbers.inject [] do |links, n|
# detect gaps:
links << gap_marker if prev and n > prev + 1
links << page_link_or_span(n)
prev = n
links
end
end
def visible_page_numbers
inner_window, outer_window = @options[:inner_window].to_i, @options[:outer_window].to_i
window_from = current_page - inner_window
window_to = current_page + inner_window
# adjust lower or upper limit if other is out of bounds
if window_to > total_pages
window_from -= window_to - total_pages
window_to = total_pages
elsif window_from < 1
window_to += 1 - window_from
window_from = 1
end
visible = (1..total_pages).to_a
left_gap = (2 + outer_window)...window_from
right_gap = (window_to + 1)...(total_pages - outer_window)
visible -= left_gap.to_a if left_gap.last - left_gap.first > 1
visible -= right_gap.to_a if right_gap.last - right_gap.first > 1
visible
end
def page_link_or_span(page, span_class = 'current', text = nil)
text ||= page.to_s
if page and page != current_page
@template.link_to text, url_options(page)
else
@template.content_tag :span, text, :class => span_class
end
end
def url_options(page)
options = { param_name => page }
# page links should preserve GET parameters
options = params.merge(options) if @template.request.get?
options.rec_merge!(@options[:params]) if @options[:params]
return options
end
private
def current_page
@collection.current_page
end
def total_pages
@collection.page_count
end
def param_name
@param_name ||= @options[:param_name].to_sym
end
def params
@params ||= @template.params.to_hash.symbolize_keys
end
end
end

@ -1,131 +0,0 @@
require File.dirname(__FILE__) + '/helper'
require 'will_paginate/core_ext'
class ArrayPaginationTest < Test::Unit::TestCase
def test_simple
collection = ('a'..'e').to_a
[{ :page => 1, :per_page => 3, :expected => %w( a b c ) },
{ :page => 2, :per_page => 3, :expected => %w( d e ) },
{ :page => 1, :per_page => 5, :expected => %w( a b c d e ) },
{ :page => 3, :per_page => 5, :expected => [] },
].
each do |conditions|
assert_equal conditions[:expected], collection.paginate(conditions.slice(:page, :per_page))
end
end
def test_defaults
result = (1..50).to_a.paginate
assert_equal 1, result.current_page
assert_equal 30, result.size
end
def test_deprecated_api
assert_deprecated 'paginate API' do
result = (1..50).to_a.paginate(2, 10)
assert_equal 2, result.current_page
assert_equal (11..20).to_a, result
assert_equal 50, result.total_entries
end
assert_deprecated { [].paginate nil }
end
def test_total_entries_has_precedence
result = %w(a b c).paginate :total_entries => 5
assert_equal 5, result.total_entries
end
def test_argument_error_with_params_and_another_argument
assert_raise ArgumentError do
[].paginate({}, 5)
end
end
def test_paginated_collection
entries = %w(a b c)
collection = create(2, 3, 10) do |pager|
assert_equal entries, pager.replace(entries)
end
assert_equal entries, collection
assert_respond_to_all collection, %w(page_count each offset size current_page per_page total_entries)
assert_kind_of Array, collection
assert_instance_of Array, collection.entries
assert_equal 3, collection.offset
assert_equal 4, collection.page_count
assert !collection.out_of_bounds?
end
def test_out_of_bounds
entries = create(2, 3, 2){}
assert entries.out_of_bounds?
entries = create(1, 3, 2){}
assert !entries.out_of_bounds?
end
def test_guessing_total_count
entries = create do |pager|
# collection is shorter than limit
pager.replace array
end
assert_equal 8, entries.total_entries
entries = create(2, 5, 10) do |pager|
# collection is shorter than limit, but we have an explicit count
pager.replace array
end
assert_equal 10, entries.total_entries
entries = create do |pager|
# collection is the same as limit; we can't guess
pager.replace array(5)
end
assert_equal nil, entries.total_entries
entries = create do |pager|
# collection is empty; we can't guess
pager.replace array(0)
end
assert_equal nil, entries.total_entries
end
def test_invalid_page
bad_input = [0, -1, nil, '', 'Schnitzel']
bad_input.each do |bad|
assert_raise(WillPaginate::InvalidPage) { create(bad) }
end
end
def test_invalid_per_page_setting
assert_raise(ArgumentError) { create(1, -1) }
end
private
def create(page = 2, limit = 5, total = nil, &block)
if block_given?
WillPaginate::Collection.create(page, limit, total, &block)
else
WillPaginate::Collection.new(page, limit, total)
end
end
def array(size = 3)
Array.new(size)
end
def collect_deprecations
old_behavior = WillPaginate::Deprecation.behavior
deprecations = []
WillPaginate::Deprecation.behavior = Proc.new do |message, callstack|
deprecations << message
end
result = yield
[result, deprecations]
ensure
WillPaginate::Deprecation.behavior = old_behavior
end
end

@ -1,23 +0,0 @@
plugin_root = File.join(File.dirname(__FILE__), '..')
version = ENV['RAILS_VERSION']
version = nil if version and version == ""
# first look for a symlink to a copy of the framework
if !version and framework_root = ["#{plugin_root}/rails", "#{plugin_root}/../../rails"].find { |p| File.directory? p }
puts "found framework root: #{framework_root}"
# this allows for a plugin to be tested outside of an app and without Rails gems
$:.unshift "#{framework_root}/activesupport/lib", "#{framework_root}/activerecord/lib", "#{framework_root}/actionpack/lib"
else
# simply use installed gems if available
puts "using Rails#{version ? ' ' + version : nil} gems"
require 'rubygems'
if version
gem 'rails', version
else
gem 'actionpack'
gem 'activerecord'
end
end
$:.unshift "#{plugin_root}/lib"

@ -1,9 +0,0 @@
#!/usr/bin/env ruby
irb = RUBY_PLATFORM =~ /(:?mswin|mingw)/ ? 'irb.bat' : 'irb'
libs = []
dirname = File.dirname(__FILE__)
libs << 'irb/completion'
libs << File.join(dirname, 'lib', 'load_fixtures')
exec "#{irb}#{libs.map{ |l| " -r #{l}" }.join} --simple-prompt"

@ -1,22 +0,0 @@
sqlite3:
database: ":memory:"
adapter: sqlite3
timeout: 500
sqlite2:
database: ":memory:"
adapter: sqlite2
mysql:
adapter: mysql
username: rails
password: mislav
encoding: utf8
database: will_paginate_unittest
postgres:
adapter: postgresql
username: mislav
password: mislav
database: will_paginate_unittest
min_messages: warning

@ -1,322 +0,0 @@
require File.dirname(__FILE__) + '/helper'
require File.dirname(__FILE__) + '/lib/activerecord_test_case'
require 'will_paginate'
WillPaginate.enable_activerecord
class FinderTest < ActiveRecordTestCase
fixtures :topics, :replies, :users, :projects, :developers_projects
def test_new_methods_presence
assert_respond_to_all Topic, %w(per_page paginate paginate_by_sql)
end
def test_simple_paginate
entries = Topic.paginate :page => nil
assert_equal 1, entries.current_page
assert_nil entries.previous_page
assert_nil entries.next_page
assert_equal 1, entries.page_count
assert_equal 4, entries.size
entries = Topic.paginate :page => 2
assert_equal 2, entries.current_page
assert_equal 1, entries.previous_page
assert_equal 1, entries.page_count
assert entries.empty?
end
def test_parameter_api
# :page parameter in options is required!
assert_raise(ArgumentError){ Topic.paginate }
assert_raise(ArgumentError){ Topic.paginate({}) }
# explicit :all should not break anything
assert_equal Topic.paginate(:page => nil), Topic.paginate(:all, :page => 1)
# :count could be nil and we should still not cry
assert_nothing_raised { Topic.paginate :page => 1, :count => nil }
end
def test_paginate_with_per_page
entries = Topic.paginate :page => 1, :per_page => 1
assert_equal 1, entries.size
assert_equal 4, entries.page_count
# Developer class has explicit per_page at 10
entries = Developer.paginate :page => 1
assert_equal 10, entries.size
assert_equal 2, entries.page_count
entries = Developer.paginate :page => 1, :per_page => 5
assert_equal 11, entries.total_entries
assert_equal 5, entries.size
assert_equal 3, entries.page_count
end
def test_paginate_with_order
entries = Topic.paginate :page => 1, :order => 'created_at desc'
expected = [topics(:futurama), topics(:harvey_birdman), topics(:rails), topics(:ar)].reverse
assert_equal expected, entries.to_a
assert_equal 1, entries.page_count
end
def test_paginate_with_conditions
entries = Topic.paginate :page => 1, :conditions => ["created_at > ?", 30.minutes.ago]
expected = [topics(:rails), topics(:ar)]
assert_equal expected, entries.to_a
assert_equal 1, entries.page_count
end
def test_paginate_with_include_and_conditions
entries = Topic.paginate \
:page => 1,
:include => :replies,
:conditions => "replies.content LIKE 'Bird%' ",
:per_page => 10
expected = Topic.find :all,
:include => 'replies',
:conditions => "replies.content LIKE 'Bird%' ",
:limit => 10
assert_equal expected, entries.to_a
assert_equal 1, entries.total_entries
end
def test_paginate_with_include_and_order
entries = Topic.paginate \
:page => 1,
:include => :replies,
:order => 'replies.created_at asc, topics.created_at asc',
:per_page => 10
expected = Topic.find :all,
:include => 'replies',
:order => 'replies.created_at asc, topics.created_at asc',
:limit => 10
assert_equal expected, entries.to_a
assert_equal 4, entries.total_entries
end
def test_paginate_associations_with_include
entries, project = nil, projects(:active_record)
assert_nothing_raised "THIS IS A BUG in Rails 1.2.3 that was fixed in [7326]. " +
"Please upgrade to the 1-2-stable branch or edge Rails." do
entries = project.topics.paginate \
:page => 1,
:include => :replies,
:conditions => "replies.content LIKE 'Nice%' ",
:per_page => 10
end
expected = Topic.find :all,
:include => 'replies',
:conditions => "project_id = #{project.id} AND replies.content LIKE 'Nice%' ",
:limit => 10
assert_equal expected, entries.to_a
end
def test_paginate_associations
dhh = users :david
expected_name_ordered = [projects(:action_controller), projects(:active_record)]
expected_id_ordered = [projects(:active_record), projects(:action_controller)]
# with association-specified order
entries = dhh.projects.paginate(:page => 1)
assert_equal expected_name_ordered, entries
assert_equal 2, entries.total_entries
# with explicit order
entries = dhh.projects.paginate(:page => 1, :order => 'projects.id')
assert_equal expected_id_ordered, entries
assert_equal 2, entries.total_entries
assert_nothing_raised { dhh.projects.find(:all, :order => 'projects.id', :limit => 4) }
entries = dhh.projects.paginate(:page => 1, :order => 'projects.id', :per_page => 4)
assert_equal expected_id_ordered, entries
# has_many with implicit order
topic = Topic.find(1)
expected = [replies(:spam), replies(:witty_retort)]
assert_equal expected.map(&:id).sort, topic.replies.paginate(:page => 1).map(&:id).sort
assert_equal expected.reverse, topic.replies.paginate(:page => 1, :order => 'replies.id ASC')
end
def test_paginate_association_extension
project = Project.find(:first)
entries = project.replies.paginate_recent :page => 1
assert_equal [replies(:brave)], entries
end
def test_paginate_with_joins
entries = Developer.paginate :page => 1,
:joins => 'LEFT JOIN developers_projects ON users.id = developers_projects.developer_id',
:conditions => 'project_id = 1'
assert_equal 2, entries.size
developer_names = entries.map { |d| d.name }
assert developer_names.include?('David')
assert developer_names.include?('Jamis')
expected = entries.to_a
entries = Developer.paginate :page => 1,
:joins => 'LEFT JOIN developers_projects ON users.id = developers_projects.developer_id',
:conditions => 'project_id = 1', :count => { :select => "users.id" }
assert_equal expected, entries.to_a
end
def test_paginate_with_group
entries = Developer.paginate :page => 1, :per_page => 10,
:group => 'salary', :select => 'salary', :order => 'salary'
expected = [ users(:david), users(:jamis), users(:dev_10), users(:poor_jamis) ].map(&:salary).sort
assert_equal expected, entries.map(&:salary)
end
def test_paginate_with_dynamic_finder
expected = [replies(:witty_retort), replies(:spam)]
assert_equal expected, Reply.paginate_by_topic_id(1, :page => 1)
entries = Developer.paginate :conditions => { :salary => 100000 }, :page => 1, :per_page => 5
assert_equal 8, entries.total_entries
assert_equal entries, Developer.paginate_by_salary(100000, :page => 1, :per_page => 5)
# dynamic finder + conditions
entries = Developer.paginate_by_salary(100000, :page => 1,
:conditions => ['id > ?', 6])
assert_equal 4, entries.total_entries
assert_equal (7..10).to_a, entries.map(&:id)
assert_raises NoMethodError do
Developer.paginate_by_inexistent_attribute 100000, :page => 1
end
end
def test_scoped_paginate
entries = Developer.with_poor_ones { Developer.paginate :page => 1 }
assert_equal 2, entries.size
assert_equal 2, entries.total_entries
end
def test_readonly
assert_nothing_raised { Developer.paginate :readonly => true, :page => 1 }
end
# this functionality is temporarily removed
def xtest_pagination_defines_method
pager = "paginate_by_created_at"
assert !User.methods.include?(pager), "User methods should not include `#{pager}` method"
# paginate!
assert 0, User.send(pager, nil, :page => 1).total_entries
# the paging finder should now be defined
assert User.methods.include?(pager), "`#{pager}` method should be defined on User"
end
# Is this Rails 2.0? Find out by testing find_all which was removed in [6998]
unless Developer.respond_to? :find_all
def test_paginate_array_of_ids
# AR finders also accept arrays of IDs
# (this was broken in Rails before [6912])
entries = Developer.paginate((1..8).to_a, :per_page => 3, :page => 2, :order => 'id')
assert_equal (4..6).to_a, entries.map(&:id)
assert_equal 8, entries.total_entries
end
end
uses_mocha 'internals' do
def test_implicit_all_with_dynamic_finders
Topic.expects(:find_all_by_foo).returns([])
Topic.expects(:count).returns(0)
Topic.paginate_by_foo :page => 1
end
def test_guessing_the_total_count
Topic.expects(:find).returns(Array.new(2))
Topic.expects(:count).never
entries = Topic.paginate :page => 2, :per_page => 4
assert_equal 6, entries.total_entries
end
def test_extra_parameters_stay_untouched
Topic.expects(:find).with(:all, {:foo => 'bar', :limit => 4, :offset => 0 }).returns(Array.new(5))
Topic.expects(:count).with({:foo => 'bar'}).returns(1)
Topic.paginate :foo => 'bar', :page => 1, :per_page => 4
end
def test_count_skips_select
Developer.stubs(:find).returns([])
Developer.expects(:count).with({}).returns(0)
Developer.paginate :select => 'salary', :page => 1
end
def test_count_select_when_distinct
Developer.stubs(:find).returns([])
Developer.expects(:count).with(:select => 'DISTINCT salary').returns(0)
Developer.paginate :select => 'DISTINCT salary', :page => 1
end
def test_should_use_scoped_finders_if_present
# scope-out compatibility
Topic.expects(:find_best).returns(Array.new(5))
Topic.expects(:with_best).returns(1)
Topic.paginate_best :page => 1, :per_page => 4
end
def test_paginate_by_sql
assert_respond_to Developer, :paginate_by_sql
Developer.expects(:find_by_sql).with(regexp_matches(/sql LIMIT 3(,| OFFSET) 3/)).returns([])
Developer.expects(:count_by_sql).with('SELECT COUNT(*) FROM (sql) AS count_table').returns(0)
entries = Developer.paginate_by_sql 'sql', :page => 2, :per_page => 3
end
def test_paginate_by_sql_respects_total_entries_setting
Developer.expects(:find_by_sql).returns([])
Developer.expects(:count_by_sql).never
entries = Developer.paginate_by_sql 'sql', :page => 1, :total_entries => 999
assert_equal 999, entries.total_entries
end
def test_paginate_by_sql_strips_order_by_when_counting
Developer.expects(:find_by_sql).returns([])
Developer.expects(:count_by_sql).with("SELECT COUNT(*) FROM (sql\n ) AS count_table").returns(0)
entries = Developer.paginate_by_sql "sql\n ORDER\nby foo, bar, `baz` ASC", :page => 1
end
# TODO: counts are still wrong
def test_ability_to_use_with_custom_finders
# acts_as_taggable defines find_tagged_with(tag, options)
Topic.expects(:find_tagged_with).with('will_paginate', :offset => 0, :limit => 5).returns([])
Topic.expects(:count).with({}).returns(0)
Topic.paginate_tagged_with 'will_paginate', :page => 1, :per_page => 5
end
def test_array_argument_doesnt_eliminate_count
ids = (1..8).to_a
Developer.expects(:find_all_by_id).returns([])
Developer.expects(:count).returns(0)
Developer.paginate_by_id(ids, :per_page => 3, :page => 2, :order => 'id')
end
def test_paginating_finder_doesnt_mangle_options
Developer.expects(:find).returns([])
Developer.expects(:count).returns(0)
options = { :page => 1 }
options.expects(:delete).never
options_before = options.dup
Developer.paginate(options)
assert_equal options, options_before
end
end
end

@ -1,3 +0,0 @@
class Admin < User
has_many :companies, :finder_sql => 'SELECT * FROM companies'
end

@ -1,11 +0,0 @@
class Developer < User
has_and_belongs_to_many :projects, :include => :topics, :order => 'projects.name'
def self.with_poor_ones(&block)
with_scope :find => { :conditions => ['salary <= ?', 80000], :order => 'salary' } do
yield
end
end
def self.per_page() 10 end
end

@ -1,13 +0,0 @@
david_action_controller:
developer_id: 1
project_id: 2
joined_on: 2004-10-10
david_active_record:
developer_id: 1
project_id: 1
joined_on: 2004-10-10
jamis_active_record:
developer_id: 2
project_id: 1

@ -1,15 +0,0 @@
class Project < ActiveRecord::Base
has_and_belongs_to_many :developers, :uniq => true
has_many :topics
# :finder_sql => 'SELECT * FROM topics WHERE (topics.project_id = #{id})',
# :counter_sql => 'SELECT COUNT(*) FROM topics WHERE (topics.project_id = #{id})'
has_many :replies, :through => :topics do
def find_recent(params = {})
with_scope :find => { :conditions => ['replies.created_at > ?', 15.minutes.ago] } do
find :all, params
end
end
end
end

@ -1,7 +0,0 @@
action_controller:
id: 2
name: Active Controller
active_record:
id: 1
name: Active Record

@ -1,29 +0,0 @@
witty_retort:
id: 1
topic_id: 1
content: Birdman is better!
created_at: <%= 6.hours.ago.to_s(:db) %>
another:
id: 2
topic_id: 2
content: Nuh uh!
created_at: <%= 1.hour.ago.to_s(:db) %>
spam:
id: 3
topic_id: 1
content: Nice site!
created_at: <%= 1.hour.ago.to_s(:db) %>
decisive:
id: 4
topic_id: 4
content: "I'm getting to the bottom of this"
created_at: <%= 30.minutes.ago.to_s(:db) %>
brave:
id: 5
topic_id: 4
content: "AR doesn't scare me a bit"
created_at: <%= 10.minutes.ago.to_s(:db) %>

@ -1,5 +0,0 @@
class Reply < ActiveRecord::Base
belongs_to :topic, :include => [:replies]
validates_presence_of :content
end

@ -1,38 +0,0 @@
ActiveRecord::Schema.define do
create_table "users", :force => true do |t|
t.column "name", :text
t.column "salary", :integer, :default => 70000
t.column "created_at", :datetime
t.column "updated_at", :datetime
t.column "type", :text
end
create_table "projects", :force => true do |t|
t.column "name", :text
end
create_table "developers_projects", :id => false, :force => true do |t|
t.column "developer_id", :integer, :null => false
t.column "project_id", :integer, :null => false
t.column "joined_on", :date
t.column "access_level", :integer, :default => 1
end
create_table "topics", :force => true do |t|
t.column "project_id", :integer
t.column "title", :string
t.column "subtitle", :string
t.column "content", :text
t.column "created_at", :datetime
t.column "updated_at", :datetime
end
create_table "replies", :force => true do |t|
t.column "content", :text
t.column "created_at", :datetime
t.column "updated_at", :datetime
t.column "topic_id", :integer
end
end

@ -1,4 +0,0 @@
class Topic < ActiveRecord::Base
has_many :replies, :dependent => :destroy, :order => 'replies.created_at DESC'
belongs_to :project
end

@ -1,30 +0,0 @@
futurama:
id: 1
title: Isnt futurama awesome?
subtitle: It really is, isnt it.
content: I like futurama
created_at: <%= 1.day.ago.to_s(:db) %>
updated_at:
harvey_birdman:
id: 2
title: Harvey Birdman is the king of all men
subtitle: yup
content: He really is
created_at: <%= 2.hours.ago.to_s(:db) %>
updated_at:
rails:
id: 3
project_id: 1
title: Rails is nice
subtitle: It makes me happy
content: except when I have to hack internals to fix pagination. even then really.
created_at: <%= 20.minutes.ago.to_s(:db) %>
ar:
id: 4
project_id: 1
title: ActiveRecord sometimes freaks me out
content: "I mean, what's the deal with eager loading?"
created_at: <%= 15.minutes.ago.to_s(:db) %>

@ -1,2 +0,0 @@
class User < ActiveRecord::Base
end

@ -1,35 +0,0 @@
david:
id: 1
name: David
salary: 80000
type: Developer
jamis:
id: 2
name: Jamis
salary: 150000
type: Developer
<% for digit in 3..10 %>
dev_<%= digit %>:
id: <%= digit %>
name: fixture_<%= digit %>
salary: 100000
type: Developer
<% end %>
poor_jamis:
id: 11
name: Jamis
salary: 9000
type: Developer
admin:
id: 12
name: admin
type: Admin
goofy:
id: 13
name: Goofy
type: Admin

@ -1,25 +0,0 @@
require 'test/unit'
require 'rubygems'
# gem install redgreen for colored test output
begin require 'redgreen'; rescue LoadError; end
require File.join(File.dirname(__FILE__), 'boot') unless defined?(ActiveRecord)
class Test::Unit::TestCase
protected
def assert_respond_to_all object, methods
methods.each do |method|
[method.to_s, method.to_sym].each { |m| assert_respond_to object, m }
end
end
end
# Wrap tests that use Mocha and skip if unavailable.
def uses_mocha(test_name)
require 'mocha' unless Object.const_defined?(:Mocha)
rescue LoadError => load_error
$stderr.puts "Skipping #{test_name} tests. `gem install mocha` and try again."
else
yield
end

@ -1,23 +0,0 @@
require File.join(File.dirname(__FILE__), 'activerecord_test_connector')
class ActiveRecordTestCase < Test::Unit::TestCase
# Set our fixture path
if ActiveRecordTestConnector.able_to_connect
self.fixture_path = File.join(File.dirname(__FILE__), '..', 'fixtures')
self.use_transactional_fixtures = true
end
def self.fixtures(*args)
super if ActiveRecordTestConnector.connected
end
def run(*args)
super if ActiveRecordTestConnector.connected
end
# Default so Test::Unit::TestCase doesn't complain
def test_truth
end
end
ActiveRecordTestConnector.setup

@ -1,60 +0,0 @@
require 'active_record'
require 'active_record/version'
require 'active_record/fixtures'
class ActiveRecordTestConnector
cattr_accessor :able_to_connect
cattr_accessor :connected
# Set our defaults
self.connected = false
self.able_to_connect = true
def self.setup
unless self.connected || !self.able_to_connect
setup_connection
load_schema
# require_fixture_models
Dependencies.load_paths.unshift(File.dirname(__FILE__) + "/../fixtures")
self.connected = true
end
rescue Exception => e # errors from ActiveRecord setup
$stderr.puts "\nSkipping ActiveRecord assertion tests: #{e}"
#$stderr.puts " #{e.backtrace.join("\n ")}\n"
self.able_to_connect = false
end
private
def self.setup_connection
db = ENV['DB'].blank?? 'sqlite3' : ENV['DB']
configurations = YAML.load_file(File.join(File.dirname(__FILE__), '..', 'database.yml'))
raise "no configuration for '#{db}'" unless configurations.key? db
configuration = configurations[db]
ActiveRecord::Base.logger = Logger.new(STDOUT) if $0 == 'irb'
puts "using #{configuration['adapter']} adapter" unless ENV['DB'].blank?
ActiveRecord::Base.establish_connection(configuration)
ActiveRecord::Base.configurations = { db => configuration }
ActiveRecord::Base.connection
unless Object.const_defined?(:QUOTED_TYPE)
Object.send :const_set, :QUOTED_TYPE, ActiveRecord::Base.connection.quote_column_name('type')
end
end
def self.load_schema
ActiveRecord::Base.silence do
ActiveRecord::Migration.verbose = false
load File.dirname(__FILE__) + "/../fixtures/schema.rb"
end
end
def self.require_fixture_models
models = Dir.glob(File.dirname(__FILE__) + "/../fixtures/*.rb")
models = (models.grep(/user.rb/) + models).uniq
models.each { |f| require f }
end
end

@ -1,21 +0,0 @@
require 'action_controller/test_process'
module HTML
class Node
def inner_text
children.map(&:inner_text).join('')
end
end
class Text
def inner_text
self.to_s
end
end
class Tag
def inner_text
childless?? '' : super
end
end
end

@ -1,13 +0,0 @@
dirname = File.dirname(__FILE__)
require File.join(dirname, '..', 'boot')
require File.join(dirname, 'activerecord_test_connector')
# setup the connection
ActiveRecordTestConnector.setup
# load all fixtures
fixture_path = File.join(dirname, '..', 'fixtures')
Fixtures.create_fixtures(fixture_path, ActiveRecord::Base.connection.tables)
require 'will_paginate'
WillPaginate.enable_activerecord

@ -1,242 +0,0 @@
require File.dirname(__FILE__) + '/helper'
require 'action_controller'
require File.dirname(__FILE__) + '/lib/html_inner_text'
ActionController::Routing::Routes.draw do |map|
map.connect ':controller/:action/:id'
end
ActionController::Base.perform_caching = false
require 'will_paginate'
WillPaginate.enable_actionpack
class PaginationTest < Test::Unit::TestCase
class DevelopersController < ActionController::Base
def list_developers
@options = session[:wp] || {}
@developers = (1..11).to_a.paginate(
:page => params[@options[:param_name] || :page] || 1,
:per_page => params[:per_page] || 4
)
render :inline => '<%= will_paginate @developers, @options %>'
end
def guess_collection_name
@developers = session[:wp]
@options = session[:wp_options]
render :inline => '<%= will_paginate @options %>'
end
protected
def rescue_errors(e) raise e end
def rescue_action(e) raise e end
end
def setup
@controller = DevelopersController.new
@request = ActionController::TestRequest.new
@response = ActionController::TestResponse.new
super
end
def test_will_paginate
get :list_developers
entries = assigns :developers
assert entries
assert_equal 4, entries.size
assert_select 'div.pagination', 1, 'no main DIV' do |pagination|
assert_select 'a[href]', 3 do |elements|
validate_page_numbers [2,3,2], elements
assert_select elements.last, ':last-child', "Next &raquo;"
end
assert_select 'span', 2
assert_select 'span.disabled:first-child', "&laquo; Previous"
assert_select 'span.current', entries.current_page.to_s
assert_equal '&laquo; Previous 1 2 3 Next &raquo;', pagination.first.inner_text
end
end
def test_will_paginate_with_options
get :list_developers, { :page => 2 }, :wp => {
:class => 'will_paginate', :prev_label => 'Prev', :next_label => 'Next'
}
assert_response :success
entries = assigns :developers
assert entries
assert_equal 4, entries.size
assert_select 'div.will_paginate', 1, 'no main DIV' do
assert_select 'a[href]', 4 do |elements|
validate_page_numbers [1,1,3,3], elements
assert_select elements.first, 'a', "Prev"
assert_select elements.last, 'a', "Next"
end
assert_select 'span.current', entries.current_page.to_s
end
end
def test_will_paginate_without_container
get :list_developers, {}, :wp => { :container => false }
assert_select 'div.pagination', 0, 'no main DIV'
assert_select 'a[href]', 3
end
def test_will_paginate_without_page_links
get :list_developers, { :page => 2 }, :wp => { :page_links => false }
assert_select 'a[href]', 2 do |elements|
validate_page_numbers [1,3], elements
end
end
def test_will_paginate_preserves_parameters_on_get
get :list_developers, :foo => { :bar => 'baz' }
assert_links_match /foo%5Bbar%5D=baz/
end
def test_will_paginate_doesnt_preserve_parameters_on_post
post :list_developers, :foo => 'bar'
assert_no_links_match /foo=bar/
end
def test_adding_additional_parameters
get :list_developers, {}, :wp => { :params => { :foo => 'bar' } }
assert_links_match /foo=bar/
end
def test_removing_arbitrary_parameters
get :list_developers, { :foo => 'bar' }, :wp => { :params => { :foo => nil } }
assert_no_links_match /foo=bar/
end
def test_adding_additional_route_parameters
get :list_developers, {}, :wp => { :params => { :controller => 'baz' } }
assert_links_match %r{\Wbaz/list_developers\W}
end
def test_will_paginate_with_custom_page_param
get :list_developers, { :developers_page => 2 }, :wp => { :param_name => :developers_page }
assert_response :success
entries = assigns :developers
assert entries
assert_equal 4, entries.size
assert_select 'div.pagination', 1, 'no main DIV' do
assert_select 'a[href]', 4 do |elements|
validate_page_numbers [1,1,3,3], elements, :developers_page
end
assert_select 'span.current', entries.current_page.to_s
end
end
def test_will_paginate_windows
get :list_developers, { :page => 6, :per_page => 1 }, :wp => { :inner_window => 1 }
assert_response :success
entries = assigns :developers
assert entries
assert_equal 1, entries.size
assert_select 'div.pagination', 1, 'no main DIV' do |pagination|
assert_select 'a[href]', 8 do |elements|
validate_page_numbers [5,1,2,5,7,10,11,7], elements
assert_select elements.first, 'a', "&laquo; Previous"
assert_select elements.last, 'a', "Next &raquo;"
end
assert_select 'span.current', entries.current_page.to_s
assert_equal '&laquo; Previous 1 2 ... 5 6 7 ... 10 11 Next &raquo;', pagination.first.inner_text
end
end
def test_will_paginate_eliminates_small_gaps
get :list_developers, { :page => 6, :per_page => 1 }, :wp => { :inner_window => 2 }
assert_response :success
assert_select 'div.pagination', 1, 'no main DIV' do
assert_select 'a[href]', 12 do |elements|
validate_page_numbers [5,1,2,3,4,5,7,8,9,10,11,7], elements
end
end
end
def test_no_pagination
get :list_developers, :per_page => 12
entries = assigns :developers
assert_equal 1, entries.page_count
assert_equal 11, entries.size
assert_equal '', @response.body
end
def test_faulty_input_raises_error
assert_raise WillPaginate::InvalidPage do
get :list_developers, :page => 'foo'
end
end
uses_mocha 'helper internals' do
def test_collection_name_can_be_guessed
collection = mock
collection.expects(:page_count).returns(1)
get :guess_collection_name, {}, :wp => collection
end
end
def test_inferred_collection_name_raises_error_when_nil
ex = assert_raise ArgumentError do
get :guess_collection_name, {}, :wp => nil
end
assert ex.message.include?('@developers')
end
def test_setting_id_for_container
get :list_developers
assert_select 'div.pagination', 1 do |div|
assert_nil div.first['id']
end
# magic ID
get :list_developers, {}, :wp => { :id => true }
assert_select 'div.pagination', 1 do |div|
assert_equal 'fixnums_pagination', div.first['id']
end
# explicit ID
get :list_developers, {}, :wp => { :id => 'custom_id' }
assert_select 'div.pagination', 1 do |div|
assert_equal 'custom_id', div.first['id']
end
end
protected
def validate_page_numbers expected, links, param_name = :page
param_pattern = /\W#{param_name}=([^&]*)/
assert_equal(expected, links.map { |e|
e['href'] =~ param_pattern
$1 ? $1.to_i : $1
})
end
def assert_links_match pattern
assert_select 'div.pagination a[href]' do |elements|
elements.each do |el|
assert_match pattern, el['href']
end
end
end
def assert_no_links_match pattern
assert_select 'div.pagination a[href]' do |elements|
elements.each do |el|
assert_no_match pattern, el['href']
end
end
end
end