jekyll-paginate-v2-redux 1.7.6

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 (32) hide show
  1. checksums.yaml +7 -0
  2. data/CODE_OF_CONDUCT.md +86 -0
  3. data/Gemfile +8 -0
  4. data/LICENSE +22 -0
  5. data/README-AUTOPAGES.md +104 -0
  6. data/README-GENERATOR.md +520 -0
  7. data/README.md +77 -0
  8. data/Rakefile +16 -0
  9. data/jekyll-paginate-v2-redux.gemspec +32 -0
  10. data/lib/jekyll-paginate-v2-redux.rb +34 -0
  11. data/lib/jekyll-paginate-v2-redux/autopages/autoPages.rb +77 -0
  12. data/lib/jekyll-paginate-v2-redux/autopages/defaults.rb +29 -0
  13. data/lib/jekyll-paginate-v2-redux/autopages/pages/baseAutoPage.rb +60 -0
  14. data/lib/jekyll-paginate-v2-redux/autopages/pages/categoryAutoPage.rb +28 -0
  15. data/lib/jekyll-paginate-v2-redux/autopages/pages/collectionAutoPage.rb +28 -0
  16. data/lib/jekyll-paginate-v2-redux/autopages/pages/tagAutoPage.rb +28 -0
  17. data/lib/jekyll-paginate-v2-redux/autopages/utils.rb +74 -0
  18. data/lib/jekyll-paginate-v2-redux/generator/compatibilityUtils.rb +121 -0
  19. data/lib/jekyll-paginate-v2-redux/generator/defaults.rb +24 -0
  20. data/lib/jekyll-paginate-v2-redux/generator/paginationGenerator.rb +141 -0
  21. data/lib/jekyll-paginate-v2-redux/generator/paginationIndexer.rb +93 -0
  22. data/lib/jekyll-paginate-v2-redux/generator/paginationModel.rb +358 -0
  23. data/lib/jekyll-paginate-v2-redux/generator/paginationPage.rb +50 -0
  24. data/lib/jekyll-paginate-v2-redux/generator/paginator.rb +84 -0
  25. data/lib/jekyll-paginate-v2-redux/generator/utils.rb +109 -0
  26. data/lib/jekyll-paginate-v2-redux/version.rb +10 -0
  27. data/spec/generator/defaults_spec.rb +34 -0
  28. data/spec/generator/paginationPage_spec.rb +12 -0
  29. data/spec/generator/paginator_spec.rb +107 -0
  30. data/spec/generator/utils_spec.rb +67 -0
  31. data/spec/spec_helper.rb +13 -0
  32. metadata +139 -0
@@ -0,0 +1,50 @@
1
+ module Jekyll
2
+ module PaginateV2::Generator
3
+
4
+ #
5
+ # This page handles the creation of the fake pagination pages based on the original page configuration
6
+ # The code does the same things as the default Jekyll/page.rb code but just forces the code to look
7
+ # into the template instead of the (currently non-existing) pagination page.
8
+ #
9
+ # This page exists purely in memory and is not read from disk
10
+ #
11
+ class PaginationPage < Page
12
+ def initialize(page_to_copy, cur_page_nr, total_pages)
13
+ @site = page_to_copy.site
14
+ @base = ''
15
+ @url = ''
16
+ @name = 'index.html'
17
+
18
+ self.process(@name) # Creates the basename and ext member values
19
+
20
+ # Only need to copy the data part of the page as it already contains the layout information
21
+ #self.data = Marshal.load(Marshal.dump(page_to_copy.data)) # Deep copying, http://stackoverflow.com/a/8206537/779521
22
+ self.data = Jekyll::Utils.deep_merge_hashes( page_to_copy.data, {} )
23
+ if !page_to_copy.data['autopage']
24
+ self.content = page_to_copy.content
25
+ else
26
+ # If the page is an auto page then migrate the necessary autopage info across into the
27
+ # new pagination page (so that users can get the correct keys etc)
28
+ if( page_to_copy.data['autopage'].has_key?('display_name') )
29
+ self.data['autopages'] = Jekyll::Utils.deep_merge_hashes( page_to_copy.data['autopage'], {} )
30
+ end
31
+ end
32
+
33
+ # Store the current page and total page numbers in the pagination_info construct
34
+ self.data['pagination_info'] = {"curr_page" => cur_page_nr, 'total_pages' => total_pages }
35
+
36
+ # Perform some validation that is also performed in Jekyll::Page
37
+ validate_data! page_to_copy.path
38
+ validate_permalink! page_to_copy.path
39
+
40
+ # Trigger a page event
41
+ #Jekyll::Hooks.trigger :pages, :post_init, self
42
+ end
43
+
44
+ def set_url(url_value)
45
+ @url = url_value
46
+ end
47
+ end # class PaginationPage
48
+
49
+ end # module PaginateV2
50
+ end # module Jekyll
@@ -0,0 +1,84 @@
1
+ module Jekyll
2
+ module PaginateV2::Generator
3
+
4
+ #
5
+ # Handles the preparation of all the posts based on the current page index
6
+ #
7
+ class Paginator
8
+ attr_reader :page, :per_page, :posts, :total_posts, :total_pages,
9
+ :previous_page, :previous_page_path, :next_page, :next_page_path, :page_path, :page_trail
10
+
11
+ def page_trail
12
+ @page_trail
13
+ end
14
+
15
+ def page_trail=(page_array)
16
+ @page_trail = page_array
17
+ end
18
+
19
+ # Initialize a new Paginator.
20
+ #
21
+ def initialize(config_per_page, first_index_page_url, paginated_page_url, posts, cur_page_nr, num_pages)
22
+ @page = cur_page_nr
23
+ @per_page = config_per_page.to_i
24
+ @total_pages = num_pages
25
+
26
+ if @page > @total_pages
27
+ raise RuntimeError, "page number can't be greater than total pages: #{@page} > #{@total_pages}"
28
+ end
29
+
30
+ init = (@page - 1) * @per_page
31
+ offset = (init + @per_page - 1) >= posts.size ? posts.size : (init + @per_page - 1)
32
+
33
+ @total_posts = posts.size
34
+ @posts = posts[init..offset]
35
+ @page_path = @page == 1 ? first_index_page_url : Utils.format_page_number(paginated_page_url, cur_page_nr, @total_pages)
36
+ @previous_page = @page != 1 ? @page - 1 : nil
37
+ @previous_page_path = @page != 1 ? @page == 2 ? first_index_page_url : Utils.format_page_number(paginated_page_url, @previous_page, @total_pages) : nil
38
+ @next_page = @page != @total_pages ? @page + 1 : nil
39
+ @next_page_path = @page != @total_pages ? Utils.format_page_number(paginated_page_url, @next_page, @total_pages) : nil
40
+ end
41
+
42
+ # Convert this Paginator's data to a Hash suitable for use by Liquid.
43
+ #
44
+ # Returns the Hash representation of this Paginator.
45
+ def to_liquid
46
+ {
47
+ 'per_page' => per_page,
48
+ 'posts' => posts,
49
+ 'total_posts' => total_posts,
50
+ 'total_pages' => total_pages,
51
+ 'page' => page,
52
+ 'page_path' => page_path,
53
+ 'previous_page' => previous_page,
54
+ 'previous_page_path' => previous_page_path,
55
+ 'next_page' => next_page,
56
+ 'next_page_path' => next_page_path,
57
+ 'page_trail' => page_trail
58
+ }
59
+ end
60
+
61
+ end # class Paginator
62
+
63
+ # Small utility class that handles individual pagination trails
64
+ # and makes them easier to work with in Liquid
65
+ class PageTrail
66
+ attr_reader :num, :path, :title
67
+
68
+ def initialize( num, path, title )
69
+ @num = num
70
+ @path = path
71
+ @title = title
72
+ end #func initialize
73
+
74
+ def to_liquid
75
+ {
76
+ 'num' => num,
77
+ 'path' => path+"index.html",
78
+ 'title' => title
79
+ }
80
+ end
81
+ end #class PageTrail
82
+
83
+ end # module PaginateV2
84
+ end # module Jekyll
@@ -0,0 +1,109 @@
1
+ module Jekyll
2
+ module PaginateV2::Generator
3
+
4
+ #
5
+ # Static utility functions that are used in the code and
6
+ # don't belong in once place in particular
7
+ #
8
+ class Utils
9
+
10
+ # Static: Calculate the number of pages.
11
+ #
12
+ # all_posts - The Array of all Posts.
13
+ # per_page - The Integer of entries per page.
14
+ #
15
+ # Returns the Integer number of pages.
16
+ def self.calculate_number_of_pages(all_posts, per_page)
17
+ (all_posts.size.to_f / per_page.to_i).ceil
18
+ end
19
+
20
+ # Static: returns a fully formatted string with the current (:num) page number and maximum (:max) page count replaced if configured
21
+ #
22
+ def self.format_page_number(toFormat, cur_page_nr, total_page_count=nil)
23
+ s = toFormat.sub(':num', cur_page_nr.to_s)
24
+ if !total_page_count.nil?
25
+ s = s.sub(':max', total_page_count.to_s)
26
+ end
27
+ return s
28
+ end #function format_page_number
29
+
30
+ # Static: returns a fully formatted string with the :title variable and the current (:num) page number and maximum (:max) page count replaced
31
+ #
32
+ def self.format_page_title(toFormat, title, cur_page_nr=nil, total_page_count=nil)
33
+ return format_page_number(toFormat.sub(':title', title.to_s), cur_page_nr, total_page_count)
34
+ end #function format_page_title
35
+
36
+ # Static: Return a String version of the input which has a leading slash.
37
+ # If the input already has a forward slash in position zero, it will be
38
+ # returned unchanged.
39
+ #
40
+ # path - a String path
41
+ #
42
+ # Returns the path with a leading slash
43
+ def self.ensure_leading_slash(path)
44
+ path[0..0] == "/" ? path : "/#{path}"
45
+ end
46
+
47
+ # Static: Return a String version of the input without a leading slash.
48
+ #
49
+ # path - a String path
50
+ #
51
+ # Returns the input without the leading slash
52
+ def self.remove_leading_slash(path)
53
+ path[0..0] == "/" ? path[1..-1] : path
54
+ end
55
+
56
+ # Static: Return a String version of the input which has a trailing slash.
57
+ # If the input already has a forward slash at the end, it will be
58
+ # returned unchanged.
59
+ #
60
+ # path - a String path
61
+ #
62
+ # Returns the path with a trailing slash
63
+ def self.ensure_trailing_slash(path)
64
+ path[-1] == "/" ? path : "#{path}/"
65
+ end
66
+
67
+ #
68
+ # Sorting routine used for ordering posts by custom fields.
69
+ # Handles Strings separately as we want a case-insenstive sorting
70
+ #
71
+ def self.sort_values(a, b)
72
+ if a.is_a?(String)
73
+ return a.downcase <=> b.downcase
74
+ end
75
+
76
+ # By default use the built in sorting for the data type
77
+ return a <=> b
78
+ end
79
+
80
+ # Retrieves the given sort field from the given post
81
+ # the sort_field variable can be a hierarchical value on the form "parent_field:child_field" repeated as many times as needed
82
+ # only the leaf child_field will be retrieved
83
+ def self.sort_get_post_data(post_data, sort_field)
84
+
85
+ # Begin by splitting up the sort_field by (;,:.)
86
+ sort_split = sort_field.split(":")
87
+ sort_value = post_data
88
+
89
+ for r_key in sort_split
90
+ key = r_key.downcase.strip # Remove any erronious whitespace and convert to lower case
91
+ if !sort_value.has_key?(key)
92
+ return nil
93
+ end
94
+ # Work my way through the hash
95
+ sort_value = sort_value[key]
96
+ end
97
+
98
+ # If the sort value is a hash then return nil else return the value
99
+ if( sort_value.is_a?(Hash) )
100
+ return nil
101
+ else
102
+ return sort_value
103
+ end
104
+ end
105
+
106
+ end
107
+
108
+ end # module PaginateV2
109
+ end # module Jekyll
@@ -0,0 +1,10 @@
1
+ module Jekyll
2
+ module PaginateV2
3
+ VERSION = "1.7.6"
4
+ # When modifying remember to issue a new tag command in git before committing, then push the new tag
5
+ # git tag -a v1.7.6 -m "Gem v1.7.6"
6
+ # git push origin --tags
7
+ # Yanking a published Gem
8
+ # gem yank jekyll-paginate-v2 -v VERSION
9
+ end # module PaginateV2
10
+ end # module Jekyll
@@ -0,0 +1,34 @@
1
+ require_relative '../spec_helper.rb'
2
+
3
+ module Jekyll::PaginateV2::Generator
4
+ describe "checking default config" do
5
+
6
+ it "should always contain the following keys" do
7
+ DEFAULT.must_include 'enabled'
8
+ DEFAULT.must_include 'collection'
9
+ DEFAULT.must_include 'per_page'
10
+ DEFAULT.must_include 'permalink'
11
+ DEFAULT.must_include 'title'
12
+ DEFAULT.must_include 'page_num'
13
+ DEFAULT.must_include 'sort_reverse'
14
+ DEFAULT.must_include 'sort_field'
15
+ DEFAULT.must_include 'limit'
16
+ DEFAULT.must_include 'debug'
17
+ DEFAULT.size.must_be :>=, 10
18
+ end
19
+
20
+ it "should always contain the following key defaults" do
21
+ DEFAULT['enabled'].must_equal false
22
+ DEFAULT['collection'].must_equal 'posts'
23
+ DEFAULT['per_page'].must_equal 10
24
+ DEFAULT['permalink'].must_equal '/page:num/'
25
+ DEFAULT['title'].must_equal ':title - page :num'
26
+ DEFAULT['page_num'].must_equal 1
27
+ DEFAULT['sort_reverse'].must_equal false
28
+ DEFAULT['sort_field'].must_equal 'date'
29
+ DEFAULT['limit'].must_equal 0
30
+ DEFAULT['debug'].must_equal false
31
+ end
32
+
33
+ end
34
+ end
@@ -0,0 +1,12 @@
1
+ require_relative '../spec_helper.rb'
2
+
3
+ module Jekyll::PaginateV2::Generator
4
+ describe "tesing pagination page implementation" do
5
+
6
+ it "sould always read the template file into itself" do
7
+ # DUE TO THE JEKYLL:PAGE CLASS ACCESSING FILE IO DIRECTLY
8
+ # I AM UNABLE TO MOCK OUT THE FILE OPERATIONS TO CREATE UNIT TESTS FOR THIS CLASS :/
9
+ end
10
+
11
+ end
12
+ end
@@ -0,0 +1,107 @@
1
+ require_relative '../spec_helper.rb'
2
+
3
+ module Jekyll::PaginateV2::Generator
4
+ describe Paginator do
5
+
6
+ it "must include the necessary paginator attributes" do
7
+
8
+ # config_per_page, first_index_page_url, paginated_page_url, posts, cur_page_nr, num_pages
9
+ pager = Paginator.new(10, "index.html", "/page:num/", [], 1, 10)
10
+
11
+ # None of these accessors should throw errors, just run through them to test
12
+ val = pager.page
13
+ val = pager.per_page
14
+ val = pager.posts
15
+ val = pager.total_posts
16
+ val = pager.total_pages
17
+ val = pager.previous_page
18
+ val = pager.previous_page_path
19
+ val = pager.next_page
20
+ val = pager.next_page_path
21
+
22
+ end
23
+
24
+ it "must throw an error if the current page number is greater than the total pages" do
25
+ err = -> { pager = Paginator.new(10, "index.html", "/page:num/", [], 10, 8) }.must_raise RuntimeError
26
+
27
+ # No error should be raised below
28
+ pager = Paginator.new(10, "index.html", "/page:num/", [], 8, 10)
29
+ end
30
+
31
+ it "must trim the list of posts correctly based on the cur_page_nr and per_page" do
32
+ # Create a dummy list of posts that is easy to track
33
+ posts = ['1','2','3','4','5','6','7','8','9','10','11','12','13','14','15','16','17','18','19','20','21','22','23','24','25','26','27','28','29','30','31','32','33','34','35']
34
+
35
+ # Initialize a pager with
36
+ # 5 posts per page
37
+ # at page 2 out of 5 pages
38
+ pager = Paginator.new(5, "index.html", "/page:num/", posts, 2, 5)
39
+
40
+ pager.page.must_equal 2
41
+ pager.per_page.must_equal 5
42
+ pager.total_pages.must_equal 5
43
+
44
+ pager.total_posts.must_equal 35
45
+
46
+ pager.posts.size.must_equal 5
47
+ pager.posts[0].must_equal '6'
48
+ pager.posts[4].must_equal '10'
49
+
50
+ pager.previous_page.must_equal 1
51
+ pager.previous_page_path.must_equal 'index.html'
52
+ pager.next_page.must_equal 3
53
+ pager.next_page_path.must_equal '/page3/'
54
+ end
55
+
56
+ it "must not create a previous page if we're at first page" do
57
+ # Create a dummy list of posts that is easy to track
58
+ posts = ['1','2','3','4','5','6','7','8','9','10','11','12','13','14','15','16','17','18','19','20','21','22','23','24','25','26','27','28','29','30','31','32','33','34','35']
59
+
60
+ # Initialize a pager with
61
+ # 5 posts per page
62
+ # at page 2 out of 5 pages
63
+ pager = Paginator.new(5, "index.html", "/page:num/", posts, 1, 5)
64
+
65
+ pager.page.must_equal 1
66
+ pager.per_page.must_equal 5
67
+ pager.total_pages.must_equal 5
68
+
69
+ pager.total_posts.must_equal 35
70
+
71
+ pager.posts.size.must_equal 5
72
+ pager.posts[0].must_equal '1'
73
+ pager.posts[4].must_equal '5'
74
+
75
+ pager.previous_page.must_be_nil
76
+ pager.previous_page_path.must_be_nil
77
+ pager.next_page.must_equal 2
78
+ pager.next_page_path.must_equal '/page2/'
79
+ end
80
+
81
+ it "must not create a next page if we're at the final page" do
82
+ # Create a dummy list of posts that is easy to track
83
+ posts = ['1','2','3','4','5','6','7','8','9','10','11','12','13','14','15','16','17','18','19','20','21','22','23','24','25','26','27','28','29','30','31','32','33','34','35']
84
+
85
+ # Initialize a pager with
86
+ # 5 posts per page
87
+ # at page 2 out of 5 pages
88
+ pager = Paginator.new(5, "index.html", "/page:num/", posts, 5, 5)
89
+
90
+ pager.page.must_equal 5
91
+ pager.per_page.must_equal 5
92
+ pager.total_pages.must_equal 5
93
+
94
+ pager.total_posts.must_equal 35
95
+
96
+ pager.posts.size.must_equal 5
97
+ pager.posts[0].must_equal '21'
98
+ pager.posts[4].must_equal '25'
99
+
100
+ pager.previous_page.must_equal 4
101
+ pager.previous_page_path.must_equal '/page4/'
102
+ pager.next_page.must_be_nil
103
+ pager.next_page_path.must_be_nil
104
+ end
105
+
106
+ end
107
+ end
@@ -0,0 +1,67 @@
1
+ require_relative '../spec_helper.rb'
2
+
3
+ module Jekyll::PaginateV2::Generator
4
+ describe Utils do
5
+
6
+ it "should always replace num format with the specified number" do
7
+ Utils.format_page_number( ":num", 7).must_equal "7"
8
+ Utils.format_page_number( ":num", 13).must_equal "13"
9
+ Utils.format_page_number( ":num", -2).must_equal "-2"
10
+ Utils.format_page_number( ":num", 0).must_equal "0"
11
+ Utils.format_page_number( ":num", 1000).must_equal "1000"
12
+ end
13
+
14
+ it "should always replace num format with the specified number and keep rest of formatting" do
15
+ Utils.format_page_number( "/page:num/", 7).must_equal "/page7/"
16
+ Utils.format_page_number( "/page:num/", 50).must_equal "/page50/"
17
+ Utils.format_page_number( "/page:num/", -5).must_equal "/page-5/"
18
+
19
+ Utils.format_page_number( "/car/:num/", 1).must_equal "/car/1/"
20
+ Utils.format_page_number( "/car/:num", 1).must_equal "/car/1"
21
+ Utils.format_page_number( "car/:num", 1).must_equal "car/1"
22
+ Utils.format_page_number( "/car//:num", 1).must_equal "/car//1"
23
+ end
24
+
25
+ it "make sure there is a leading slash in path" do
26
+ Utils.ensure_leading_slash("path/to/file/wow").must_equal "/path/to/file/wow"
27
+ Utils.ensure_leading_slash("/no/place/wow/").must_equal "/no/place/wow/"
28
+ Utils.ensure_leading_slash("/no").must_equal "/no"
29
+ Utils.ensure_leading_slash("no").must_equal "/no"
30
+ end
31
+
32
+ it "make sure there is never a leading slash in path" do
33
+ Utils.remove_leading_slash("path/to/file/wow").must_equal "path/to/file/wow"
34
+ Utils.remove_leading_slash("/no/place/wow/").must_equal "no/place/wow/"
35
+ Utils.remove_leading_slash("/no").must_equal "no"
36
+ Utils.remove_leading_slash("no").must_equal "no"
37
+ end
38
+
39
+ it "sort must sort strings lowercase" do
40
+ Utils.sort_values( "AARON", "Aaron").must_equal 0
41
+ Utils.sort_values( "AARON", "aaron").must_equal 0
42
+ Utils.sort_values( "aaron", "AARON").must_equal 0
43
+ end
44
+
45
+ it "when sorting by nested post data the values must be resolved fully" do
46
+ data = {'book'=>{ 'name' => { 'first'=> 'John', 'last'=> 'Smith'}, 'rank'=>20}}
47
+ Utils.sort_get_post_data(data, "book:rank").must_equal 20
48
+ Utils.sort_get_post_data(data, "book:name:first").must_equal "John"
49
+ Utils.sort_get_post_data(data, "book:name:last").must_equal "Smith"
50
+
51
+ Utils.sort_get_post_data(data, "book:name").must_be_nil
52
+ Utils.sort_get_post_data(data, "name").must_be_nil
53
+ Utils.sort_get_post_data(data, "book").must_be_nil
54
+ end
55
+
56
+ it "should always replace max format with the specified number if specified" do
57
+ Utils.format_page_number( ":num-:max", 7, 16).must_equal "7-16"
58
+ Utils.format_page_number( ":num-:max", 13, 20).must_equal "13-20"
59
+ Utils.format_page_number( ":num-:max", -2, -4).must_equal "-2--4"
60
+ Utils.format_page_number( ":num_of_:max", 0, 10).must_equal "0_of_10"
61
+ Utils.format_page_number( ":num/:max", 1000, 2000).must_equal "1000/2000"
62
+ end
63
+
64
+
65
+ end
66
+ end
67
+