diff options
32 files changed, 1620 insertions, 3 deletions
diff --git a/app/controllers/request_controller.rb b/app/controllers/request_controller.rb index 2756b9452..b1c27ecb6 100644 --- a/app/controllers/request_controller.rb +++ b/app/controllers/request_controller.rb @@ -4,7 +4,7 @@ # Copyright (c) 2007 UK Citizens Online Democracy. All rights reserved. # Email: francis@mysociety.org; WWW: http://www.mysociety.org/ # -# $Id: request_controller.rb,v 1.10 2007-10-31 12:14:20 francis Exp $ +# $Id: request_controller.rb,v 1.11 2007-11-01 05:44:43 francis Exp $ class RequestController < ApplicationController @@ -15,7 +15,7 @@ class RequestController < ApplicationController end def list - @info_request_pages, @info_requests = paginate :info_requests, :per_page => 25, :order => "created_at desc" + @info_requests = InfoRequest.paginate :order => "created_at desc", :page => params[:page], :per_page => 25 end def frontpage diff --git a/app/views/request/list.rhtml b/app/views/request/list.rhtml index 815c440b9..b898e83f5 100644 --- a/app/views/request/list.rhtml +++ b/app/views/request/list.rhtml @@ -23,7 +23,7 @@ </table> <p> -<%= pagination_links(@info_request_pages) %> +<%= will_paginate(@info_requests) %> </p> diff --git a/vendor/plugins/will_paginate/LICENSE b/vendor/plugins/will_paginate/LICENSE new file mode 100644 index 000000000..96a48cb3f --- /dev/null +++ b/vendor/plugins/will_paginate/LICENSE @@ -0,0 +1,18 @@ +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. diff --git a/vendor/plugins/will_paginate/README b/vendor/plugins/will_paginate/README new file mode 100644 index 000000000..24bda4085 --- /dev/null +++ b/vendor/plugins/will_paginate/README @@ -0,0 +1,119 @@ += WillPaginate + +Pagination is just limiting the number of records displayed. Why should you let +it get in your way while doing more important tasks on your project? This +plugin makes magic happen. Ever wanted to be able to do just this: + + Post.paginate :page => 1 + +... and then render the page links with a single call to a view helper? Well, +now you can. Simply: + + script/plugin install svn://errtheblog.com/svn/plugins/will_paginate + +Ryan Bates made an awesome screencast[http://railscasts.com/episodes/51], check +it out. + + +== Example usage: + +Use a paginate finder in the controller: + + @posts = Post.paginate_by_board_id @board.id, :page => params[:page] + +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 ++Post.per_page+. 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 30 if missing.) +You can also 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, but 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 %> + + +== Authors, credits, contact! + +REPORT BUGS on Lighthouse: http://err.lighthouseapp.com/projects/466-plugins/overview + +BROWSE SOURCE on Warehouse: http://plugins.require.errtheblog.com/browser/will_paginate + +Want to discuss, request features, ask questions? Join the Google group: +http://groups.google.com/group/will_paginate + + Ruby port by: PJ Hyett, Mislav Marohnić (Sulien) + Original announcement: http://errtheblog.com/post/929 + Original PHP source: http://www.strangerstudios.com/sandbox/pagination/diggstyle.php + Contributors: Chris Wanstrath, Dr. Nic Williams, K. Adam Christensen, + Mike Garey, Bence Golda, Matt Aimonetti, Charles Brian Quinn, + Desi McAdam, James Coglan, Matijs van Zuijlen + +== Want Digg style? + +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; + } diff --git a/vendor/plugins/will_paginate/Rakefile b/vendor/plugins/will_paginate/Rakefile new file mode 100644 index 000000000..9a81ef503 --- /dev/null +++ b/vendor/plugins/will_paginate/Rakefile @@ -0,0 +1,26 @@ +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 + +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' +end diff --git a/vendor/plugins/will_paginate/init.rb b/vendor/plugins/will_paginate/init.rb new file mode 100644 index 000000000..9a774d107 --- /dev/null +++ b/vendor/plugins/will_paginate/init.rb @@ -0,0 +1,4 @@ +unless ActiveRecord::Base.respond_to? :paginate + require 'will_paginate' + WillPaginate.enable +end 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 000000000..74e69c164 --- /dev/null +++ b/vendor/plugins/will_paginate/lib/will_paginate.rb @@ -0,0 +1,57 @@ +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 + def enable + enable_actionpack + enable_activerecord + end + + def enable_actionpack + return if ActionView::Base.instance_methods.include? 'will_paginate' + require 'will_paginate/view_helpers' + ActionView::Base.class_eval { include ViewHelpers } + end + + 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 + 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 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 000000000..d435a5f08 --- /dev/null +++ b/vendor/plugins/will_paginate/lib/will_paginate/collection.rb @@ -0,0 +1,113 @@ +module WillPaginate + # 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 + @per_page = per_page.to_i + + 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 defines pagination on 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 or with a number smaller than 1 + def out_of_bounds? + current_page > page_count or current_page < 1 + 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 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 000000000..23cc43079 --- /dev/null +++ b/vendor/plugins/will_paginate/lib/will_paginate/core_ext.rb @@ -0,0 +1,61 @@ +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 + +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] || 1 + 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 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 000000000..74dc176cc --- /dev/null +++ b/vendor/plugins/will_paginate/lib/will_paginate/finder.rb @@ -0,0 +1,174 @@ +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 + define_method(:per_page) { 30 } unless respond_to?(:per_page) + end + end + + # = Paginating finders for ActiveRecord models + # + # WillPaginate doesn't really add extra methods to your ActiveRecord models (except +per_page+ + # unless it's already available). It simply intercepts + # the calls to paginating finders such as +paginate+, +paginate_by_user_id+ (and so on) and + # translates them to ordinary finders: +find+, +find_by_user_id+, etc. It does so with some + # method_missing magic, but you don't need to care for that. You simply use paginating finders + # same way you used ordinary ones. You only need to tell them what page you want in options. + # + # @topics = Topic.paginate :all, :page => params[:page] + # + # In paginating finders, "all" is implicit. No sense in paginating a single record, right? So: + # + # Post.paginate => Post.find :all + # Post.paginate_all_by_something => Post.find_all_by_something + # Post.paginate_by_something => Post.find_all_by_something + # + # Knowing that, the above example can be written simply as: + # + # @topics = Topic.paginate :page => params[:page] + # + # Don't forget to pass the +page+ parameter! Without it, paginating finders will raise an error. + # + # == Options + # Options for paginating finders are: + # + # page REQUIRED, but defaults to 1 if false or nil + # per_page (default is read from the model, which is 30 if not overridden) + # total entries not needed unless you want to count the records yourself somehow + # count hash of options that are used only for the call to count + # + module ClassMethods + # This methods 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 + # + def paginate_by_sql(sql, options) + options, page, per_page = wp_parse_options!(options) + + WillPaginate::Collection.create(page, per_page) do |pager| + query = sanitize_sql(sql) + count_query = "SELECT COUNT(*) FROM (#{query}) AS count_table" unless options[:total_entries] + options.update :offset => pager.offset, :limit => pager.per_page + + add_limit! query, options + pager.replace find_by_sql(query) + + pager.total_entries = options[:total_entries] || count_by_sql(count_query) unless pager.total_entries + end + end + + def respond_to?(method, include_priv = false) + 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) + # 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 + + options, page, per_page, total_entries = wp_parse_options!(args.pop) + # an array of IDs may have been given: + total_entries ||= (Array === args.first and args.first.size) + + # paginate finders are really just find_* with limit and offset + finder = method.to_s.sub /^paginate/, 'find' + + # :all is implicit, naturally + if finder == 'find' + args.unshift(:all) if args.empty? + elsif finder.index('find_by_') == 0 + finder.sub! 'find', 'find_all' + end + + WillPaginate::Collection.create(page, per_page, total_entries) do |pager| + args << options.except(:count).merge(:offset => pager.offset, :limit => pager.per_page) + pager.replace send(finder, *args) + + # magic counting for user convenience: + pager.total_entries = wp_count!(options, args, finder) unless pager.total_entries + end + end + + def wp_count!(options, args, finder) + excludees = [:count, :order, :limit, :offset] + unless options[:select] and options[:select] =~ /^\s*DISTINCT/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.delete(:count) || {}) if options.key? :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 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 conditions = wp_extract_finder_conditions(finder, args) + # extracted the conditions from calls like "paginate_by_foo_and_bar" + with_scope(:find => { :conditions => conditions }, &counter) + else + counter.call + end + + count.respond_to?(:length) ? count.length : count + end + + def wp_parse_options!(options) + raise ArgumentError, 'hash parameters expected' unless options.respond_to? :symbolize_keys! + 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 parameters' + end + + page = options.delete(:page) || 1 + per_page = options.delete(:per_page) || self.per_page + total = options.delete(:total_entries) + [options, page, per_page, total] + end + + private + + # thanks to active record for making us duplicate this code + def wp_extract_finder_conditions(finder, arguments) + return unless match = /^find_(all_by|by)_([_a-zA-Z]\w*)$/.match(finder.to_s) + + attribute_names = extract_attribute_names_from_match(match) + unless all_attributes_exists?(attribute_names) + raise "I can't make sense of `#{finder}`. Try doing the count manually" + end + construct_attributes_from_arguments(attribute_names, arguments) + end + end + end +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 000000000..b3702fc09 --- /dev/null +++ b/vendor/plugins/will_paginate/lib/will_paginate/view_helpers.rb @@ -0,0 +1,136 @@ +require 'will_paginate/core_ext' + +module WillPaginate + # = Global options for pagination 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 => '« Previous', + :next_label => 'Next »', + :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 + } + mattr_reader :pagination_options + + # Renders Digg-style pagination. (We know you wanna!) + # Returns nil if there is only one page in total (can't paginate that). + # + # Options for will_paginate view helper: + # + # class: CSS class name for the generated DIV (default "pagination") + # prev_label: default '« Previous', + # next_label: default 'Next »', + # inner_window: how many links are shown around the current page, defaults to 4 + # outer_window: how many links are around the first and the last page, defaults to 1 + # separator: string separator for page HTML elements, default " " (single space) + # param_name: parameter name for page number in URLs, defaults to "page" + # + # All extra options are passed to the generated container DIV, so eventually + # they become its HTML attributes. + # + def will_paginate(entries = @entries, options = {}) + total_pages = + + if entries.page_count > 1 + renderer = WillPaginate::LinkRenderer.new entries, options, self + links = renderer.items + + content_tag :div, links, renderer.html_options + end + 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.symbolize_keys.reverse_merge WillPaginate::ViewHelpers.pagination_options + @template = template + end + + def items + returning windowed_paginator do |links| + # next and previous 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]) + end.join(@options[:separator]) + end + + def html_options + @options.except *(WillPaginate::ViewHelpers.pagination_options.keys - [:class]) + end + + protected + + def windowed_paginator + inner_window, outer_window = @options[:inner_window].to_i, @options[:outer_window].to_i + min = page - inner_window + max = page + inner_window + # adjust lower or upper limit if other is out of bounds + if max > total_pages then min -= max - total_pages + elsif min < 1 then max += 1 - min + end + + current = min..max + beginning = 1..(1 + outer_window) + tail = (total_pages - outer_window)..total_pages + visible = [beginning, current, tail].map(&:to_a).flatten.sort.uniq + + links, prev = [], 0 + + visible.each do |n| + next if n < 1 + break if n > total_pages + + unless n - prev > 1 + prev = n + links << page_link_or_span((n != page ? n : nil), 'current', n) + else + # ellipsis represents the gap between windows + prev = n - 1 + links << '...' + redo + end + end + + links + end + + def page_link_or_span(page, span_class, text) + unless page + @template.content_tag :span, text, :class => span_class + else + # page links should preserve GET/POST parameters + @template.link_to text, @template.params.merge(param => page != 1 ? page : nil) + end + end + + private + + def page + @collection.current_page + end + + def total_pages + @collection.page_count + end + + def param + @options[:param_name].to_sym + end + end +end diff --git a/vendor/plugins/will_paginate/test/array_pagination_test.rb b/vendor/plugins/will_paginate/test/array_pagination_test.rb new file mode 100644 index 000000000..e3eaa0813 --- /dev/null +++ b/vendor/plugins/will_paginate/test/array_pagination_test.rb @@ -0,0 +1,121 @@ +require File.dirname(__FILE__) + '/helper' +require 'will_paginate' +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 => [] }, + { :page => -1, :per_page => 5, :expected => [] }, + { :page => 1, :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(0, 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 + + private + def create(page = 2, limit = 5, total = nil, &block) + WillPaginate::Collection.create(page, limit, total, &block) + 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 diff --git a/vendor/plugins/will_paginate/test/boot.rb b/vendor/plugins/will_paginate/test/boot.rb new file mode 100644 index 000000000..b8db87f9d --- /dev/null +++ b/vendor/plugins/will_paginate/test/boot.rb @@ -0,0 +1,24 @@ +plugin_root = File.join(File.dirname(__FILE__), '..') + +# first look for a symlink to a copy of the framework +if 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 an app + $:.unshift "#{framework_root}/activesupport/lib", "#{framework_root}/activerecord/lib", "#{framework_root}/actionpack/lib" +else + # is the plugin installed in an application? + app_root = plugin_root + '/../../..' + + if File.directory? app_root + '/config' + puts 'using config/boot.rb' + ENV['RAILS_ENV'] = 'test' + require File.expand_path(app_root + '/config/boot') + else + # simply use installed gems if available + puts 'using rubygems' + require 'rubygems' + gem 'actionpack'; gem 'activerecord' + end +end + +$:.unshift "#{plugin_root}/lib" diff --git a/vendor/plugins/will_paginate/test/console b/vendor/plugins/will_paginate/test/console new file mode 100755 index 000000000..53b8de4f5 --- /dev/null +++ b/vendor/plugins/will_paginate/test/console @@ -0,0 +1,9 @@ +#!/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" 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 000000000..6211ee3fc --- /dev/null +++ b/vendor/plugins/will_paginate/test/finder_test.rb @@ -0,0 +1,284 @@ +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' + expected = [ users(:david), users(:jamis), users(:dev_10), users(:poor_jamis) ].map(&:salary).sort + assert_equal expected, entries.map(&:salary).sort + 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_paginate_by_sql + assert_respond_to Developer, :paginate_by_sql + entries = Developer.paginate_by_sql ['select * from users where salary > ?', 80000], + :page => 2, :per_page => 3, :total_entries => 9 + + assert_equal (5..7).to_a, entries.map(&:id) + assert_equal 9, entries.total_entries + end + + def test_count_by_sql + entries = Developer.paginate_by_sql ['select * from users where salary > ?', 60000], + :page => 2, :per_page => 3 + + assert_equal 12, entries.total_entries + end + + def test_count_distinct + entries = Developer.paginate :select => 'DISTINCT salary', :page => 1, :per_page => 4 + assert_equal 4, entries.size + assert_equal 4, entries.total_entries + end + + def test_scoped_paginate + entries = + Developer.with_poor_ones do + Developer.paginate :page => 1 + end + + assert_equal 2, entries.size + assert_equal 2, entries.total_entries + end + + # Are we on edge? 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) + assert_equal (4..6).to_a, entries.map(&:id) + assert_equal 8, entries.total_entries + end + end + + uses_mocha 'parameter' do + def test_implicit_all_with_dynamic_finders + Topic.expects(:find_all_by_foo).returns([]) + Topic.expects(:wp_extract_finder_conditions) + Topic.expects(:count) + 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() { |*args| args.last.key? :foo }.returns(Array.new(5)) + Topic.expects(:count).with(){ |*args| args.last.key? :foo }.returns(1) + + Topic.paginate :foo => 'bar', :page => 1, :per_page => 4 + end + + def test_count_doesnt_use_select_options + Developer.expects(:find).with() { |*args| args.last.key? :select }.returns(Array.new(5)) + Developer.expects(:count).with(){ |*args| !args.last.key?(:select) }.returns(1) + + Developer.paginate :select => 'users.*', :page => 1, :per_page => 4 + end + + def test_should_use_scoped_finders_if_present + 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_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 + end +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 000000000..1d5e7f36a --- /dev/null +++ b/vendor/plugins/will_paginate/test/fixtures/admin.rb @@ -0,0 +1,3 @@ +class Admin < User + has_many :companies, :finder_sql => 'SELECT * FROM companies' +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 000000000..6650a9808 --- /dev/null +++ b/vendor/plugins/will_paginate/test/fixtures/developer.rb @@ -0,0 +1,11 @@ +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 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 000000000..cee359c7c --- /dev/null +++ b/vendor/plugins/will_paginate/test/fixtures/developers_projects.yml @@ -0,0 +1,13 @@ +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
\ 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 000000000..0f85ef5ea --- /dev/null +++ b/vendor/plugins/will_paginate/test/fixtures/project.rb @@ -0,0 +1,15 @@ +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 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 000000000..02800c782 --- /dev/null +++ b/vendor/plugins/will_paginate/test/fixtures/projects.yml @@ -0,0 +1,7 @@ +action_controller: + id: 2 + name: Active Controller + +active_record: + id: 1 + name: Active Record 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 000000000..4421908ba --- /dev/null +++ b/vendor/plugins/will_paginate/test/fixtures/replies.yml @@ -0,0 +1,34 @@ +witty_retort: + id: 1 + topic_id: 1 + content: Birdman is better! + created_at: <%= 6.hours.ago.to_s(:db) %> + updated_at: nil + +another: + id: 2 + topic_id: 2 + content: Nuh uh! + created_at: <%= 1.hour.ago.to_s(:db) %> + updated_at: nil + +spam: + id: 3 + topic_id: 1 + content: Nice site! + created_at: <%= 1.hour.ago.to_s(:db) %> + updated_at: nil + +decisive: + id: 4 + topic_id: 4 + content: "I'm getting to the bottom of this" + created_at: <%= 30.minutes.ago.to_s(:db) %> + updated_at: nil + +brave: + id: 5 + topic_id: 4 + content: "AR doesn't scare me a bit" + created_at: <%= 10.minutes.ago.to_s(:db) %> + updated_at: nil 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 000000000..ea84042b9 --- /dev/null +++ b/vendor/plugins/will_paginate/test/fixtures/reply.rb @@ -0,0 +1,5 @@ +class Reply < ActiveRecord::Base + belongs_to :topic, :include => [:replies] + + validates_presence_of :content +end diff --git a/vendor/plugins/will_paginate/test/fixtures/schema.rb b/vendor/plugins/will_paginate/test/fixtures/schema.rb new file mode 100644 index 000000000..2c6d3e1c1 --- /dev/null +++ b/vendor/plugins/will_paginate/test/fixtures/schema.rb @@ -0,0 +1,38 @@ +ActiveRecord::Schema.define do + + 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 "projects", :force => true do |t| + t.column "name", :text + 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 + + 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 "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 + +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 000000000..12b8747b6 --- /dev/null +++ b/vendor/plugins/will_paginate/test/fixtures/topic.rb @@ -0,0 +1,4 @@ +class Topic < ActiveRecord::Base + has_many :replies, :dependent => :destroy, :order => 'replies.created_at DESC' + belongs_to :project +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 000000000..0a2690473 --- /dev/null +++ b/vendor/plugins/will_paginate/test/fixtures/topics.yml @@ -0,0 +1,30 @@ +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) %> 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 000000000..4a57cf079 --- /dev/null +++ b/vendor/plugins/will_paginate/test/fixtures/user.rb @@ -0,0 +1,2 @@ +class User < ActiveRecord::Base +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 000000000..ed2c03ae1 --- /dev/null +++ b/vendor/plugins/will_paginate/test/fixtures/users.yml @@ -0,0 +1,35 @@ +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 diff --git a/vendor/plugins/will_paginate/test/helper.rb b/vendor/plugins/will_paginate/test/helper.rb new file mode 100644 index 000000000..307e29af8 --- /dev/null +++ b/vendor/plugins/will_paginate/test/helper.rb @@ -0,0 +1,25 @@ +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) + yield +rescue LoadError => load_error + raise unless load_error.message =~ /mocha/i + $stderr.puts "Skipping #{test_name} tests. `gem install mocha` and try again." +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 000000000..2b20dff39 --- /dev/null +++ b/vendor/plugins/will_paginate/test/lib/activerecord_test_case.rb @@ -0,0 +1,23 @@ +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 = false + 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 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 000000000..0435f478d --- /dev/null +++ b/vendor/plugins/will_paginate/test/lib/activerecord_test_connector.rb @@ -0,0 +1,67 @@ +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 + if Object.const_defined?(:ActiveRecord) + defaults = { :database => ':memory:' } + ActiveRecord::Base.logger = Logger.new STDOUT if $0 == 'irb' + + begin + options = defaults.merge :adapter => 'sqlite3', :timeout => 500 + ActiveRecord::Base.establish_connection(options) + ActiveRecord::Base.configurations = { 'sqlite3_ar_integration' => options } + ActiveRecord::Base.connection + rescue Exception # errors from establishing a connection + $stderr.puts 'SQLite 3 unavailable; trying SQLite 2.' + options = defaults.merge :adapter => 'sqlite' + ActiveRecord::Base.establish_connection(options) + ActiveRecord::Base.configurations = { 'sqlite2_ar_integration' => options } + ActiveRecord::Base.connection + end + + unless Object.const_defined?(:QUOTED_TYPE) + Object.send :const_set, :QUOTED_TYPE, ActiveRecord::Base.connection.quote_column_name('type') + end + else + raise "Can't setup connection since ActiveRecord isn't loaded." + 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 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 000000000..c9f4d1fb0 --- /dev/null +++ b/vendor/plugins/will_paginate/test/lib/load_fixtures.rb @@ -0,0 +1,13 @@ +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 diff --git a/vendor/plugins/will_paginate/test/pagination_test.rb b/vendor/plugins/will_paginate/test/pagination_test.rb new file mode 100644 index 000000000..9d2295399 --- /dev/null +++ b/vendor/plugins/will_paginate/test/pagination_test.rb @@ -0,0 +1,146 @@ +require File.dirname(__FILE__) + '/helper' +require 'action_controller' +require 'action_controller/test_process' + +ActionController::Routing::Routes.reload rescue nil +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 PaginationController < ActionController::Base + def list_developers + @options = params.delete(:options) || {} + + @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 + + protected + def rescue_errors(e) raise e end + def rescue_action(e) raise e end + end + + def setup + @controller = PaginationController.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 |el| + assert_select 'a[href]', 3 do |elements| + validate_page_numbers [2,3,2], elements + assert_select elements.last, ':last-child', "Next »" + end + assert_select 'span', 2 + assert_select 'span.disabled:first-child', "« Previous" + assert_select 'span.current', entries.current_page.to_s + end + end + + def test_will_paginate_with_options + get :list_developers, :page => 2, :options => { + :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 [nil,nil,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_preserves_parameters + get :list_developers, :foo => { :bar => 'baz' } + assert_response :success + + assert_select 'div.pagination', 1, 'no main DIV' do + assert_select 'a[href]', 3 do |elements| + elements.each do |el| + assert_match /foo%5Bbar%5D=baz/, el['href'], "THIS IS A BUG in Rails 1.2 which " + + "has been fixed in Rails 2.0." + # there is no need to worry *unless* you too are using hashes in parameters which + # need to be preserved over pages + end + end + end + end + + def test_will_paginate_with_custom_page_param + get :list_developers, :developers_page => 2, :options => { :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 [nil,nil,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, :options => { :inner_window => 2 } + assert_response :success + + entries = assigns :developers + assert entries + assert_equal 1, entries.size + + assert_select 'div.pagination', 1, 'no main DIV' do + assert_select 'a[href]', 10 do |elements| + validate_page_numbers [5,nil,2,4,5,7,8,10,11,7], elements + assert_select elements.first, 'a', "« Previous" + assert_select elements.last, 'a', "Next »" + end + assert_select 'span.current', entries.current_page.to_s + 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 + +protected + + def validate_page_numbers expected, links, param_name = :page + assert_equal(expected, links.map { |e| + e['href'] =~ /\W#{param_name}=([^&]*)/ + $1 ? $1.to_i : $1 + }) + end +end |