will_paginate_seo 3.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (59) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +18 -0
  3. data/README.md +61 -0
  4. data/lib/will_paginate.rb +25 -0
  5. data/lib/will_paginate/active_record.rb +261 -0
  6. data/lib/will_paginate/array.rb +33 -0
  7. data/lib/will_paginate/collection.rb +136 -0
  8. data/lib/will_paginate/core_ext.rb +30 -0
  9. data/lib/will_paginate/data_mapper.rb +100 -0
  10. data/lib/will_paginate/deprecation.rb +55 -0
  11. data/lib/will_paginate/i18n.rb +22 -0
  12. data/lib/will_paginate/locale/en.yml +33 -0
  13. data/lib/will_paginate/mongoid.rb +46 -0
  14. data/lib/will_paginate/page_number.rb +57 -0
  15. data/lib/will_paginate/per_page.rb +27 -0
  16. data/lib/will_paginate/railtie.rb +68 -0
  17. data/lib/will_paginate/sequel.rb +39 -0
  18. data/lib/will_paginate/version.rb +9 -0
  19. data/lib/will_paginate/view_helpers.rb +162 -0
  20. data/lib/will_paginate/view_helpers/action_view.rb +152 -0
  21. data/lib/will_paginate/view_helpers/link_renderer.rb +131 -0
  22. data/lib/will_paginate/view_helpers/link_renderer_base.rb +77 -0
  23. data/lib/will_paginate/view_helpers/merb.rb +26 -0
  24. data/lib/will_paginate/view_helpers/sinatra.rb +41 -0
  25. data/spec/collection_spec.rb +139 -0
  26. data/spec/console +12 -0
  27. data/spec/console_fixtures.rb +28 -0
  28. data/spec/database.yml +22 -0
  29. data/spec/fake_rubygems.rb +18 -0
  30. data/spec/finders/active_record_spec.rb +517 -0
  31. data/spec/finders/activerecord_test_connector.rb +119 -0
  32. data/spec/finders/data_mapper_spec.rb +116 -0
  33. data/spec/finders/data_mapper_test_connector.rb +54 -0
  34. data/spec/finders/mongoid_spec.rb +140 -0
  35. data/spec/finders/sequel_spec.rb +67 -0
  36. data/spec/finders/sequel_test_connector.rb +15 -0
  37. data/spec/fixtures/admin.rb +3 -0
  38. data/spec/fixtures/developer.rb +16 -0
  39. data/spec/fixtures/developers_projects.yml +13 -0
  40. data/spec/fixtures/project.rb +13 -0
  41. data/spec/fixtures/projects.yml +6 -0
  42. data/spec/fixtures/replies.yml +29 -0
  43. data/spec/fixtures/reply.rb +8 -0
  44. data/spec/fixtures/schema.rb +38 -0
  45. data/spec/fixtures/topic.rb +8 -0
  46. data/spec/fixtures/topics.yml +30 -0
  47. data/spec/fixtures/user.rb +2 -0
  48. data/spec/fixtures/users.yml +35 -0
  49. data/spec/matchers/deprecation_matcher.rb +27 -0
  50. data/spec/matchers/phrase_matcher.rb +19 -0
  51. data/spec/matchers/query_count_matcher.rb +36 -0
  52. data/spec/page_number_spec.rb +65 -0
  53. data/spec/per_page_spec.rb +41 -0
  54. data/spec/spec_helper.rb +46 -0
  55. data/spec/view_helpers/action_view_spec.rb +441 -0
  56. data/spec/view_helpers/base_spec.rb +142 -0
  57. data/spec/view_helpers/link_renderer_base_spec.rb +87 -0
  58. data/spec/view_helpers/view_example_group.rb +125 -0
  59. metadata +106 -0
@@ -0,0 +1,30 @@
1
+ require 'set'
2
+
3
+ # copied from ActiveSupport so we don't depend on it
4
+
5
+ unless Hash.method_defined? :except
6
+ Hash.class_eval do
7
+ # Returns a new hash without the given keys.
8
+ def except(*keys)
9
+ rejected = Set.new(respond_to?(:convert_key) ? keys.map { |key| convert_key(key) } : keys)
10
+ reject { |key,| rejected.include?(key) }
11
+ end
12
+
13
+ # Replaces the hash without only the given keys.
14
+ def except!(*keys)
15
+ replace(except(*keys))
16
+ end
17
+ end
18
+ end
19
+
20
+ unless String.method_defined? :underscore
21
+ String.class_eval do
22
+ def underscore
23
+ self.to_s.gsub(/::/, '/').
24
+ gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
25
+ gsub(/([a-z\d])([A-Z])/,'\1_\2').
26
+ tr("-", "_").
27
+ downcase
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,100 @@
1
+ require 'dm-core'
2
+ require 'dm-aggregates'
3
+ require 'will_paginate/per_page'
4
+ require 'will_paginate/page_number'
5
+ require 'will_paginate/collection'
6
+
7
+ module WillPaginate
8
+ module DataMapper
9
+ module Pagination
10
+ def page(num)
11
+ pagenum = ::WillPaginate::PageNumber(num.nil? ? 1 : num)
12
+ per_page = query.limit || self.per_page
13
+ options = {:offset => pagenum.to_offset(per_page).to_i}
14
+ options[:limit] = per_page unless query.limit
15
+ col = new_collection(query.merge(options))
16
+ col.current_page = pagenum
17
+ col
18
+ end
19
+
20
+ def paginate(options)
21
+ options = options.dup
22
+ pagenum = options.fetch(:page) { raise ArgumentError, ":page parameter required" }
23
+ per_page = options.delete(:per_page) || self.per_page
24
+ total = options.delete(:total_entries)
25
+
26
+ options.delete(:page)
27
+ options[:limit] = per_page.to_i
28
+
29
+
30
+ col = all(options).page(pagenum)
31
+ col.total_entries = total.to_i unless total.nil? || (total.kind_of?(String) && total.strip.empty?)
32
+ col
33
+ end
34
+ end
35
+
36
+ module CollectionMethods
37
+ include WillPaginate::CollectionMethods
38
+
39
+ attr_accessor :current_page
40
+ attr_writer :total_entries
41
+
42
+ def paginated?
43
+ !current_page.nil?
44
+ end
45
+
46
+ def per_page
47
+ query.limit || model.per_page
48
+ end
49
+
50
+ def offset
51
+ query.offset
52
+ end
53
+
54
+ def total_entries
55
+ @total_entries ||= begin
56
+ if loaded? and @array.size < per_page and (current_page == 1 or @array.size > 0)
57
+ offset + @array.size
58
+ else
59
+ # :reload prevents Collection.filter from being run, which
60
+ # would cause a stack overflow
61
+ clean_query = query.merge(:reload => true)
62
+ # seems like the only way
63
+ clean_query.instance_variable_set('@limit', nil)
64
+ clean_query.instance_variable_set('@offset', 0)
65
+ new_collection(clean_query).count
66
+ end
67
+ end
68
+ end
69
+
70
+ def to_a
71
+ if paginated?
72
+ ::WillPaginate::Collection.create(current_page, per_page) do |col|
73
+ col.replace super
74
+ col.total_entries ||= total_entries
75
+ end
76
+ else
77
+ super
78
+ end
79
+ end
80
+
81
+ private
82
+
83
+ def new_collection(query, resources = nil)
84
+ col = super
85
+ col.current_page = self.current_page
86
+ col
87
+ end
88
+
89
+ def initialize_copy(original)
90
+ super
91
+ @total_entries = nil
92
+ end
93
+ end
94
+
95
+ ::DataMapper::Model.append_extensions PerPage
96
+ ::DataMapper::Model.append_extensions Pagination
97
+ ::DataMapper::Collection.send(:include, Pagination)
98
+ ::DataMapper::Collection.send(:include, CollectionMethods)
99
+ end
100
+ end
@@ -0,0 +1,55 @@
1
+ module WillPaginate::Deprecation
2
+ class << self
3
+ def warn(message, stack = caller)
4
+ offending_line = origin_of_call(stack)
5
+ full_message = "DEPRECATION WARNING: #{message} (called from #{offending_line})"
6
+ logger = rails_logger || Kernel
7
+ logger.warn full_message
8
+ end
9
+
10
+ private
11
+
12
+ def rails_logger
13
+ defined?(Rails) && Rails.logger
14
+ end
15
+
16
+ def origin_of_call(stack)
17
+ lib_root = File.expand_path('../../..', __FILE__)
18
+ stack.find { |line| line.index(lib_root) != 0 } || stack.first
19
+ end
20
+ end
21
+
22
+ class Hash < ::Hash
23
+ def initialize(values = {})
24
+ super()
25
+ update values
26
+ @deprecated = {}
27
+ end
28
+
29
+ def []=(key, value)
30
+ check_deprecated(key, value)
31
+ super
32
+ end
33
+
34
+ def deprecate_key(*keys)
35
+ message = block_given? ? Proc.new : keys.pop
36
+ Array(keys).each { |key| @deprecated[key] = message }
37
+ end
38
+
39
+ def merge(another)
40
+ to_hash.update(another)
41
+ end
42
+
43
+ def to_hash
44
+ ::Hash.new.update(self)
45
+ end
46
+
47
+ private
48
+
49
+ def check_deprecated(key, value)
50
+ if msg = @deprecated[key] and (!msg.respond_to?(:call) or (msg = msg.call(key, value)))
51
+ WillPaginate::Deprecation.warn(msg)
52
+ end
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,22 @@
1
+ module WillPaginate
2
+ module I18n
3
+ def self.locale_dir
4
+ File.expand_path('../locale', __FILE__)
5
+ end
6
+
7
+ def self.load_path
8
+ Dir["#{locale_dir}/*.{rb,yml}"]
9
+ end
10
+
11
+ def will_paginate_translate(keys, options = {})
12
+ if defined? ::I18n
13
+ defaults = Array(keys).dup
14
+ defaults << Proc.new if block_given?
15
+ ::I18n.translate(defaults.shift, options.merge(:default => defaults, :scope => :will_paginate))
16
+ else
17
+ key = Array === keys ? keys.first : keys
18
+ yield key, options
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,33 @@
1
+ en:
2
+ will_paginate:
3
+ previous_label: "&#8592; Previous"
4
+ next_label: "Next &#8594;"
5
+ page_gap: "&hellip;"
6
+
7
+ page_entries_info:
8
+ single_page:
9
+ zero: "No %{model} found"
10
+ one: "Displaying 1 %{model}"
11
+ other: "Displaying all %{count} %{model}"
12
+ single_page_html:
13
+ zero: "No %{model} found"
14
+ one: "Displaying <b>1</b> %{model}"
15
+ other: "Displaying <b>all&nbsp;%{count}</b> %{model}"
16
+
17
+ multi_page: "Displaying %{model} %{from} - %{to} of %{count} in total"
18
+ multi_page_html: "Displaying %{model} <b>%{from}&nbsp;-&nbsp;%{to}</b> of <b>%{count}</b> in total"
19
+
20
+ # models:
21
+ # entry:
22
+ # zero: entries
23
+ # one: entry
24
+ # few: entries
25
+ # other: entries
26
+
27
+ # line_item:
28
+ # page_entries_info:
29
+ # single_page:
30
+ # zero: "Your shopping cart is empty"
31
+ # one: "Displaying one item in your cart"
32
+ # other: "Displaying all %{count} items"
33
+ # multi_page: "Displaying items %{from} - %{to} of %{count} in total"
@@ -0,0 +1,46 @@
1
+ require 'mongoid'
2
+ require 'will_paginate/collection'
3
+
4
+ module WillPaginate
5
+ module Mongoid
6
+ module CriteriaMethods
7
+ def paginate(options = {})
8
+ extend CollectionMethods
9
+ @current_page = WillPaginate::PageNumber(options[:page] || @current_page || 1)
10
+ @page_multiplier = current_page - 1
11
+ pp = (options[:per_page] || per_page || WillPaginate.per_page).to_i
12
+ limit(pp).skip(@page_multiplier * pp)
13
+ end
14
+
15
+ def per_page(value = :non_given)
16
+ if value == :non_given
17
+ options[:limit] == 0 ? nil : options[:limit] # in new Mongoid versions a nil limit is saved as 0
18
+ else
19
+ limit(value)
20
+ end
21
+ end
22
+
23
+ def page(page)
24
+ paginate(:page => page)
25
+ end
26
+ end
27
+
28
+ module CollectionMethods
29
+ attr_reader :current_page
30
+
31
+ def total_entries
32
+ @total_entries ||= count
33
+ end
34
+
35
+ def total_pages
36
+ (total_entries / per_page.to_f).ceil
37
+ end
38
+
39
+ def offset
40
+ @page_multiplier * per_page
41
+ end
42
+ end
43
+
44
+ ::Mongoid::Criteria.send(:include, CriteriaMethods)
45
+ end
46
+ end
@@ -0,0 +1,57 @@
1
+ require 'delegate'
2
+ require 'forwardable'
3
+
4
+ module WillPaginate
5
+ # a module that page number exceptions are tagged with
6
+ module InvalidPage; end
7
+
8
+ # integer representing a page number
9
+ class PageNumber < DelegateClass(Integer)
10
+ # a value larger than this is not supported in SQL queries
11
+ BIGINT = 9223372036854775807
12
+
13
+ extend Forwardable
14
+
15
+ def initialize(value, name)
16
+ value = Integer(value)
17
+ if 'offset' == name ? (value < 0 or value > BIGINT) : value < 1
18
+ raise RangeError, "invalid #{name}: #{value.inspect}"
19
+ end
20
+ @name = name
21
+ super(value)
22
+ rescue ArgumentError, TypeError, RangeError => error
23
+ error.extend InvalidPage
24
+ raise error
25
+ end
26
+
27
+ alias_method :to_i, :__getobj__
28
+
29
+ def inspect
30
+ "#{@name} #{to_i}"
31
+ end
32
+
33
+ def to_offset(per_page)
34
+ PageNumber.new((to_i - 1) * per_page.to_i, 'offset')
35
+ end
36
+
37
+ def kind_of?(klass)
38
+ super || to_i.kind_of?(klass)
39
+ end
40
+ alias is_a? kind_of?
41
+ end
42
+
43
+ # Ultrahax: makes `Fixnum === current_page` checks pass
44
+ Numeric.extend Module.new {
45
+ def ===(obj)
46
+ obj.instance_of? PageNumber or super
47
+ end
48
+ }
49
+
50
+ # An idemptotent coercion method
51
+ def self.PageNumber(value, name = 'page')
52
+ case value
53
+ when PageNumber then value
54
+ else PageNumber.new(value, name)
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,27 @@
1
+ module WillPaginate
2
+ module PerPage
3
+ def per_page
4
+ defined?(@per_page) ? @per_page : WillPaginate.per_page
5
+ end
6
+
7
+ def per_page=(limit)
8
+ @per_page = limit.to_i
9
+ end
10
+
11
+ def self.extended(base)
12
+ base.extend Inheritance if base.is_a? Class
13
+ end
14
+
15
+ module Inheritance
16
+ def inherited(subclass)
17
+ super
18
+ subclass.per_page = self.per_page
19
+ end
20
+ end
21
+ end
22
+
23
+ extend PerPage
24
+
25
+ # default number of items per page
26
+ self.per_page = 30
27
+ end
@@ -0,0 +1,68 @@
1
+ require 'will_paginate'
2
+ require 'will_paginate/page_number'
3
+ require 'will_paginate/collection'
4
+ require 'will_paginate/i18n'
5
+
6
+ module WillPaginate
7
+ class Railtie < Rails::Railtie
8
+ initializer "will_paginate" do |app|
9
+ ActiveSupport.on_load :active_record do
10
+ require 'will_paginate/active_record'
11
+ end
12
+
13
+ ActiveSupport.on_load :action_controller do
14
+ WillPaginate::Railtie.setup_actioncontroller
15
+ end
16
+
17
+ ActiveSupport.on_load :action_view do
18
+ require 'will_paginate/view_helpers/action_view'
19
+ end
20
+
21
+ self.class.add_locale_path config
22
+
23
+ # early access to ViewHelpers.pagination_options
24
+ require 'will_paginate/view_helpers'
25
+ end
26
+
27
+ def self.setup_actioncontroller
28
+ ( defined?(ActionDispatch::ExceptionWrapper) ?
29
+ ActionDispatch::ExceptionWrapper : ActionDispatch::ShowExceptions
30
+ ).send :include, ShowExceptionsPatch
31
+ ActionController::Base.extend ControllerRescuePatch
32
+ end
33
+
34
+ def self.add_locale_path(config)
35
+ config.i18n.railties_load_path.unshift(*WillPaginate::I18n.load_path)
36
+ end
37
+
38
+ # Extending the exception handler middleware so it properly detects
39
+ # WillPaginate::InvalidPage regardless of it being a tag module.
40
+ module ShowExceptionsPatch
41
+ extend ActiveSupport::Concern
42
+ included { alias_method_chain :status_code, :paginate }
43
+ def status_code_with_paginate(exception = @exception)
44
+ if exception.is_a?(WillPaginate::InvalidPage) or
45
+ (exception.respond_to?(:original_exception) &&
46
+ exception.original_exception.is_a?(WillPaginate::InvalidPage))
47
+ Rack::Utils.status_code(:not_found)
48
+ else
49
+ original_method = method(:status_code_without_paginate)
50
+ if original_method.arity != 0
51
+ original_method.call(exception)
52
+ else
53
+ original_method.call()
54
+ end
55
+ end
56
+ end
57
+ end
58
+
59
+ module ControllerRescuePatch
60
+ def rescue_from(*args, &block)
61
+ if idx = args.index(WillPaginate::InvalidPage)
62
+ args[idx] = args[idx].name
63
+ end
64
+ super(*args, &block)
65
+ end
66
+ end
67
+ end
68
+ end