monad 0.0.2 → 0.0.3

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 (188) hide show
  1. checksums.yaml +7 -0
  2. data/CONTRIBUTING.markdown +91 -0
  3. data/Gemfile +1 -1
  4. data/History.markdown +772 -0
  5. data/{README.md → README.markdown} +5 -2
  6. data/Rakefile +163 -1
  7. data/bin/monad +86 -30
  8. data/features/create_sites.feature +54 -25
  9. data/features/data.feature +65 -0
  10. data/features/data_sources.feature +10 -10
  11. data/features/drafts.feature +5 -5
  12. data/features/embed_filters.feature +10 -10
  13. data/features/include_tag.feature +48 -0
  14. data/features/markdown.feature +5 -5
  15. data/features/pagination.feature +38 -10
  16. data/features/permalinks.feature +31 -11
  17. data/features/post_data.feature +41 -41
  18. data/features/post_excerpts.feature +50 -0
  19. data/features/site_configuration.feature +47 -26
  20. data/features/site_data.feature +30 -24
  21. data/features/step_definitions/{monad_steps.rb → jekyll_steps.rb} +66 -52
  22. data/features/support/env.rb +27 -8
  23. data/lib/jekyll.rb +99 -0
  24. data/lib/jekyll/cleaner.rb +73 -0
  25. data/lib/{monad → jekyll}/command.rb +6 -6
  26. data/lib/{monad → jekyll}/commands/build.rb +9 -9
  27. data/lib/jekyll/commands/doctor.rb +67 -0
  28. data/lib/jekyll/commands/new.rb +67 -0
  29. data/lib/jekyll/commands/serve.rb +65 -0
  30. data/lib/{monad → jekyll}/configuration.rb +60 -18
  31. data/lib/{monad → jekyll}/converter.rb +1 -1
  32. data/lib/{monad → jekyll}/converters/identity.rb +1 -1
  33. data/lib/{monad → jekyll}/converters/markdown.rb +2 -2
  34. data/lib/jekyll/converters/markdown/kramdown_parser.rb +29 -0
  35. data/lib/{monad → jekyll}/converters/markdown/maruku_parser.rb +12 -8
  36. data/lib/{monad → jekyll}/converters/markdown/rdiscount_parser.rb +4 -2
  37. data/lib/{monad → jekyll}/converters/markdown/redcarpet_parser.rb +1 -1
  38. data/lib/{monad → jekyll}/converters/textile.rb +1 -1
  39. data/lib/{monad → jekyll}/convertible.rb +39 -17
  40. data/lib/{monad → jekyll}/core_ext.rb +22 -4
  41. data/lib/jekyll/deprecator.rb +36 -0
  42. data/lib/{monad → jekyll}/draft.rb +1 -1
  43. data/lib/{monad → jekyll}/drivers/json_driver.rb +1 -1
  44. data/lib/{monad → jekyll}/drivers/yaml_driver.rb +1 -1
  45. data/lib/{monad → jekyll}/errors.rb +1 -1
  46. data/lib/jekyll/excerpt.rb +113 -0
  47. data/lib/{monad → jekyll}/filters.rb +16 -6
  48. data/lib/{monad → jekyll}/generator.rb +1 -1
  49. data/lib/jekyll/generators/pagination.rb +214 -0
  50. data/lib/{monad → jekyll}/layout.rb +4 -1
  51. data/lib/{monad → jekyll}/mime.types +0 -0
  52. data/lib/{monad → jekyll}/page.rb +36 -39
  53. data/lib/{monad → jekyll}/plugin.rb +1 -1
  54. data/lib/{monad → jekyll}/post.rb +58 -123
  55. data/lib/jekyll/related_posts.rb +59 -0
  56. data/lib/{monad → jekyll}/site.rb +120 -123
  57. data/lib/{monad → jekyll}/static_file.rb +1 -1
  58. data/lib/jekyll/stevenson.rb +89 -0
  59. data/lib/jekyll/tags/gist.rb +48 -0
  60. data/lib/{monad → jekyll}/tags/highlight.rb +3 -3
  61. data/lib/jekyll/tags/include.rb +135 -0
  62. data/lib/{monad → jekyll}/tags/post_url.rb +8 -6
  63. data/lib/jekyll/url.rb +67 -0
  64. data/lib/monad.rb +36 -27
  65. data/lib/site_template/_config.yml +2 -1
  66. data/lib/site_template/_layouts/default.html +21 -23
  67. data/lib/site_template/_layouts/post.html +1 -1
  68. data/lib/site_template/_posts/{0000-00-00-welcome-to-monad.markdown.erb → 0000-00-00-welcome-to-jekyll.markdown.erb} +6 -6
  69. data/lib/site_template/css/main.css +22 -27
  70. data/lib/site_template/index.html +2 -2
  71. data/monad.gemspec +153 -52
  72. data/site/.gitignore +4 -0
  73. data/site/CNAME +1 -0
  74. data/site/README +1 -0
  75. data/site/_config.yml +6 -0
  76. data/site/_includes/analytics.html +32 -0
  77. data/site/_includes/docs_contents.html +16 -0
  78. data/site/_includes/docs_contents_mobile.html +23 -0
  79. data/site/_includes/docs_option.html +11 -0
  80. data/site/_includes/docs_ul.html +20 -0
  81. data/site/_includes/footer.html +15 -0
  82. data/site/_includes/header.html +18 -0
  83. data/site/_includes/news_contents.html +23 -0
  84. data/site/_includes/news_contents_mobile.html +11 -0
  85. data/site/_includes/news_item.html +24 -0
  86. data/site/_includes/primary-nav-items.html +14 -0
  87. data/site/_includes/section_nav.html +22 -0
  88. data/site/_includes/top.html +17 -0
  89. data/site/_layouts/default.html +12 -0
  90. data/site/_layouts/docs.html +23 -0
  91. data/site/_layouts/news.html +19 -0
  92. data/site/_layouts/news_item.html +27 -0
  93. data/site/_posts/2013-05-06-jekyll-1-0-0-released.markdown +23 -0
  94. data/site/_posts/2013-05-08-jekyll-1-0-1-released.markdown +27 -0
  95. data/site/_posts/2013-05-12-jekyll-1-0-2-released.markdown +28 -0
  96. data/site/_posts/2013-06-07-jekyll-1-0-3-released.markdown +25 -0
  97. data/site/_posts/2013-07-14-jekyll-1-1-0-released.markdown +27 -0
  98. data/site/_posts/2013-07-24-jekyll-1-1-1-released.markdown +31 -0
  99. data/site/_posts/2013-07-25-jekyll-1-0-4-released.markdown +20 -0
  100. data/site/_posts/2013-07-25-jekyll-1-1-2-released.markdown +20 -0
  101. data/site/_posts/2013-09-06-jekyll-1-2-0-released.markdown +23 -0
  102. data/site/_posts/2013-09-14-jekyll-1-2-1-released.markdown +19 -0
  103. data/site/css/gridism.css +110 -0
  104. data/site/css/normalize.css +1 -0
  105. data/site/css/pygments.css +70 -0
  106. data/site/css/style.css +946 -0
  107. data/site/docs/configuration.md +373 -0
  108. data/site/docs/contributing.md +128 -0
  109. data/site/docs/datafiles.md +63 -0
  110. data/site/docs/deployment-methods.md +109 -0
  111. data/site/docs/drafts.md +20 -0
  112. data/site/docs/extras.md +56 -0
  113. data/site/docs/frontmatter.md +180 -0
  114. data/site/docs/github-pages.md +91 -0
  115. data/site/docs/heroku.md +9 -0
  116. data/site/docs/history.md +722 -0
  117. data/site/docs/index.md +52 -0
  118. data/site/docs/installation.md +76 -0
  119. data/site/docs/migrations.md +257 -0
  120. data/site/docs/pages.md +86 -0
  121. data/site/docs/pagination.md +211 -0
  122. data/site/docs/permalinks.md +180 -0
  123. data/site/docs/plugins.md +508 -0
  124. data/site/docs/posts.md +181 -0
  125. data/site/docs/quickstart.md +32 -0
  126. data/site/docs/resources.md +46 -0
  127. data/site/docs/sites.md +29 -0
  128. data/site/docs/structure.md +190 -0
  129. data/site/docs/templates.md +319 -0
  130. data/site/docs/troubleshooting.md +150 -0
  131. data/site/docs/upgrading.md +146 -0
  132. data/site/docs/usage.md +63 -0
  133. data/site/docs/variables.md +322 -0
  134. data/site/favicon.png +0 -0
  135. data/site/feed.xml +36 -0
  136. data/site/freenode.txt +1 -0
  137. data/site/img/article-footer.png +0 -0
  138. data/site/img/footer-arrow.png +0 -0
  139. data/site/img/footer-logo.png +0 -0
  140. data/site/img/logo-2x.png +0 -0
  141. data/site/img/octojekyll.png +0 -0
  142. data/site/img/tube.png +0 -0
  143. data/site/img/tube1x.png +0 -0
  144. data/site/index.html +90 -0
  145. data/site/js/modernizr-2.5.3.min.js +4 -0
  146. data/site/news/index.html +10 -0
  147. data/site/news/releases/index.html +10 -0
  148. data/test/helper.rb +6 -3
  149. data/test/source/+/foo.md +7 -0
  150. data/test/source/_data/languages.yml +2 -0
  151. data/test/source/_data/members.yaml +7 -0
  152. data/test/source/_data/products.yml +4 -0
  153. data/test/source/_includes/params.html +7 -0
  154. data/test/source/_layouts/default.html +1 -1
  155. data/test/source/_layouts/post/simple.html +1 -0
  156. data/test/source/_plugins/dummy.rb +1 -1
  157. data/test/source/_posts/2013-01-02-post-excerpt.markdown +1 -1
  158. data/test/source/_posts/2013-07-22-post-excerpt-with-layout.markdown +23 -0
  159. data/test/source/_posts/2013-08-01-mkdn-extension.mkdn +0 -0
  160. data/test/source/deal.with.dots.html +1 -1
  161. data/test/source/products.yml +4 -0
  162. data/test/test_configuration.rb +46 -11
  163. data/test/test_convertible.rb +2 -2
  164. data/test/test_excerpt.rb +78 -0
  165. data/test/test_filters.rb +4 -4
  166. data/test/test_generated_site.rb +13 -13
  167. data/test/test_json_driver.rb +9 -9
  168. data/test/test_kramdown.rb +32 -5
  169. data/test/test_new_command.rb +8 -8
  170. data/test/test_page.rb +12 -3
  171. data/test/test_pager.rb +34 -33
  172. data/test/test_post.rb +34 -26
  173. data/test/test_redcloth.rb +3 -3
  174. data/test/test_related_posts.rb +47 -0
  175. data/test/test_site.rb +102 -44
  176. data/test/test_tags.rb +168 -23
  177. data/test/test_url.rb +28 -0
  178. data/test/test_yaml_driver.rb +6 -6
  179. metadata +215 -137
  180. data/lib/monad/commands/doctor.rb +0 -29
  181. data/lib/monad/commands/new.rb +0 -50
  182. data/lib/monad/commands/serve.rb +0 -33
  183. data/lib/monad/converters/markdown/kramdown_parser.rb +0 -44
  184. data/lib/monad/deprecator.rb +0 -32
  185. data/lib/monad/generators/pagination.rb +0 -143
  186. data/lib/monad/logger.rb +0 -54
  187. data/lib/monad/tags/gist.rb +0 -30
  188. data/lib/monad/tags/include.rb +0 -37
@@ -0,0 +1,36 @@
1
+ module Jekyll
2
+ class Deprecator
3
+ def self.process(args)
4
+ no_subcommand(args)
5
+ arg_is_present? args, "--server", "The --server command has been replaced by the \
6
+ 'serve' subcommand."
7
+ arg_is_present? args, "--no-server", "To build Jekyll without launching a server, \
8
+ use the 'build' subcommand."
9
+ arg_is_present? args, "--auto", "The switch '--auto' has been replaced with '--watch'."
10
+ arg_is_present? args, "--no-auto", "To disable auto-replication, simply leave off \
11
+ the '--watch' switch."
12
+ arg_is_present? args, "--pygments", "The 'pygments' setting can only be set in \
13
+ your config files."
14
+ arg_is_present? args, "--paginate", "The 'paginate' setting can only be set in your \
15
+ config files."
16
+ arg_is_present? args, "--url", "The 'url' setting can only be set in your config files."
17
+ end
18
+
19
+ def self.no_subcommand(args)
20
+ if args.size > 0 && args.first =~ /^--/ && !%w[--help --version].include?(args.first)
21
+ Jekyll.logger.error "Deprecation:", "Jekyll now uses subcommands instead of just \
22
+ switches. Run `jekyll help' to find out more."
23
+ end
24
+ end
25
+
26
+ def self.arg_is_present?(args, deprecated_argument, message)
27
+ if args.include?(deprecated_argument)
28
+ deprecation_message(message)
29
+ end
30
+ end
31
+
32
+ def self.deprecation_message(message)
33
+ Jekyll.logger.error "Deprecation:", message
34
+ end
35
+ end
36
+ end
@@ -1,4 +1,4 @@
1
- module Monad
1
+ module Jekyll
2
2
 
3
3
  class Draft < Post
4
4
 
@@ -3,7 +3,7 @@ require 'uri'
3
3
  require 'net/http'
4
4
  require 'net/https' # ruby 1.8.7 requires explicitly require net/https
5
5
 
6
- module Monad
6
+ module Jekyll
7
7
  module Drivers
8
8
  class JsonDriver
9
9
  def initialize(options)
@@ -1,6 +1,6 @@
1
1
  require 'safe_yaml'
2
2
 
3
- module Monad
3
+ module Jekyll
4
4
  module Drivers
5
5
  class YamlDriver
6
6
  def initialize(options)
@@ -1,4 +1,4 @@
1
- module Monad
1
+ module Jekyll
2
2
  class FatalException < StandardError
3
3
  end
4
4
  end
@@ -0,0 +1,113 @@
1
+ module Jekyll
2
+ class Excerpt
3
+ include Convertible
4
+
5
+ attr_accessor :post
6
+ attr_accessor :content, :output, :ext
7
+
8
+ # Initialize this Post instance.
9
+ #
10
+ # site - The Site.
11
+ # base - The String path to the dir containing the post file.
12
+ # name - The String filename of the post file.
13
+ #
14
+ # Returns the new Post.
15
+ def initialize(post)
16
+ self.post = post
17
+ self.content = extract_excerpt(post.content)
18
+ end
19
+
20
+ %w[site name ext].each do |meth|
21
+ define_method(meth) do
22
+ post.send(meth)
23
+ end
24
+ end
25
+
26
+ def to_liquid
27
+ post.to_liquid(Post::EXCERPT_ATTRIBUTES_FOR_LIQUID)
28
+ end
29
+
30
+ # Fetch YAML front-matter data from related post, without layout key
31
+ #
32
+ # Returns Hash of post data
33
+ def data
34
+ @data ||= post.data.dup
35
+ @data.delete("layout")
36
+ @data
37
+ end
38
+
39
+ # 'Path' of the excerpt.
40
+ #
41
+ # Returns the path for the post this excerpt belongs to with #excerpt appended
42
+ def path
43
+ File.join(post.path, "#excerpt")
44
+ end
45
+
46
+ # Check if excerpt includes a string
47
+ #
48
+ # Returns true if the string passed in
49
+ def include?(something)
50
+ (self.output && self.output.include?(something)) || self.content.include?(something)
51
+ end
52
+
53
+ # The UID for this post (useful in feeds).
54
+ # e.g. /2008/11/05/my-awesome-post
55
+ #
56
+ # Returns the String UID.
57
+ def id
58
+ File.join(post.dir, post.slug, "#excerpt")
59
+ end
60
+
61
+ def to_s
62
+ self.output || self.content
63
+ end
64
+
65
+ # Returns the shorthand String identifier of this Post.
66
+ def inspect
67
+ "<Excerpt: #{self.id}>"
68
+ end
69
+
70
+ protected
71
+
72
+ # Internal: Extract excerpt from the content
73
+ #
74
+ # By default excerpt is your first paragraph of a post: everything before
75
+ # the first two new lines:
76
+ #
77
+ # ---
78
+ # title: Example
79
+ # ---
80
+ #
81
+ # First paragraph with [link][1].
82
+ #
83
+ # Second paragraph.
84
+ #
85
+ # [1]: http://example.com/
86
+ #
87
+ # This is fairly good option for Markdown and Textile files. But might cause
88
+ # problems for HTML posts (which is quite unusual for Jekyll). If default
89
+ # excerpt delimiter is not good for you, you might want to set your own via
90
+ # configuration option `excerpt_separator`. For example, following is a good
91
+ # alternative for HTML posts:
92
+ #
93
+ # # file: _config.yml
94
+ # excerpt_separator: "<!-- more -->"
95
+ #
96
+ # Notice that all markdown-style link references will be appended to the
97
+ # excerpt. So the example post above will have this excerpt source:
98
+ #
99
+ # First paragraph with [link][1].
100
+ #
101
+ # [1]: http://example.com/
102
+ #
103
+ # Excerpts are rendered same time as content is rendered.
104
+ #
105
+ # Returns excerpt String
106
+ def extract_excerpt(post_content)
107
+ separator = site.config['excerpt_separator']
108
+ head, _, tail = post_content.partition(separator)
109
+
110
+ "" << head << "\n\n" << tail.scan(/^\[[^\]]+\]:.+$/).join("\n")
111
+ end
112
+ end
113
+ end
@@ -1,6 +1,6 @@
1
1
  require 'uri'
2
2
 
3
- module Monad
3
+ module Jekyll
4
4
  module Filters
5
5
  # Convert a Textile string into HTML output.
6
6
  #
@@ -9,7 +9,7 @@ module Monad
9
9
  # Returns the HTML formatted String.
10
10
  def textilize(input)
11
11
  site = @context.registers[:site]
12
- converter = site.getConverterImpl(Monad::Converters::Textile)
12
+ converter = site.getConverterImpl(Jekyll::Converters::Textile)
13
13
  converter.convert(input)
14
14
  end
15
15
 
@@ -20,7 +20,7 @@ module Monad
20
20
  # Returns the HTML formatted String.
21
21
  def markdownify(input)
22
22
  site = @context.registers[:site]
23
- converter = site.getConverterImpl(Monad::Converters::Markdown)
23
+ converter = site.getConverterImpl(Jekyll::Converters::Markdown)
24
24
  converter.convert(input)
25
25
  end
26
26
 
@@ -99,7 +99,17 @@ module Monad
99
99
  def cgi_escape(input)
100
100
  CGI::escape(input)
101
101
  end
102
-
102
+
103
+ # URI escape a string.
104
+ #
105
+ # input - The String to escape.
106
+ #
107
+ # Examples
108
+ #
109
+ # uri_escape('foo, bar \\baz?')
110
+ # # => "foo,%20bar%20%5Cbaz?"
111
+ #
112
+ # Returns the escaped String.
103
113
  def uri_escape(input)
104
114
  URI.escape(input)
105
115
  end
@@ -140,7 +150,7 @@ module Monad
140
150
 
141
151
  # Convert the input into json string
142
152
  #
143
- # input - The Array of Hash to be converted
153
+ # input - The Array or Hash to be converted
144
154
  #
145
155
  # Returns the converted json string
146
156
  def json(input)
@@ -155,7 +165,7 @@ module Monad
155
165
  when String
156
166
  Time.parse(input)
157
167
  else
158
- Monad::Logger.error "Invalid Date:", "'#{input}' is not a valid datetime."
168
+ Jekyll.logger.error "Invalid Date:", "'#{input}' is not a valid datetime."
159
169
  exit(1)
160
170
  end
161
171
  end
@@ -1,4 +1,4 @@
1
- module Monad
1
+ module Jekyll
2
2
  class Generator < Plugin
3
3
  end
4
4
  end
@@ -0,0 +1,214 @@
1
+ module Jekyll
2
+ module Generators
3
+ class Pagination < Generator
4
+ # This generator is safe from arbitrary code execution.
5
+ safe true
6
+
7
+ # Generate paginated pages if necessary.
8
+ #
9
+ # site - The Site.
10
+ #
11
+ # Returns nothing.
12
+ def generate(site)
13
+ if Pager.pagination_enabled?(site)
14
+ if template = template_page(site)
15
+ paginate(site, template)
16
+ else
17
+ Jekyll.logger.warn "Pagination:", "Pagination is enabled, but I couldn't find" +
18
+ "an index.html page to use as the pagination template. Skipping pagination."
19
+ end
20
+ end
21
+ end
22
+
23
+ # Paginates the blog's posts. Renders the index.html file into paginated
24
+ # directories, e.g.: page2/index.html, page3/index.html, etc and adds more
25
+ # site-wide data.
26
+ #
27
+ # site - The Site.
28
+ # page - The index.html Page that requires pagination.
29
+ #
30
+ # {"paginator" => { "page" => <Number>,
31
+ # "per_page" => <Number>,
32
+ # "posts" => [<Post>],
33
+ # "total_posts" => <Number>,
34
+ # "total_pages" => <Number>,
35
+ # "previous_page" => <Number>,
36
+ # "next_page" => <Number> }}
37
+ def paginate(site, page)
38
+ all_posts = site.site_payload['site']['posts']
39
+ pages = Pager.calculate_pages(all_posts, site.config['paginate'].to_i)
40
+ (1..pages).each do |num_page|
41
+ pager = Pager.new(site, num_page, all_posts, pages)
42
+ if num_page > 1
43
+ newpage = Page.new(site, site.source, page.dir, page.name)
44
+ newpage.pager = pager
45
+ newpage.dir = Pager.paginate_path(site, num_page)
46
+ site.pages << newpage
47
+ else
48
+ page.pager = pager
49
+ end
50
+ end
51
+ end
52
+
53
+ # Static: Fetch the URL of the template page. Used to determine the
54
+ # path to the first pager in the series.
55
+ #
56
+ # site - the Jekyll::Site object
57
+ #
58
+ # Returns the url of the template page
59
+ def self.first_page_url(site)
60
+ if page = Pagination.new.template_page(site)
61
+ page.url
62
+ else
63
+ nil
64
+ end
65
+ end
66
+
67
+ # Public: Find the Jekyll::Page which will act as the pager template
68
+ #
69
+ # site - the Jekyll::Site object
70
+ #
71
+ # Returns the Jekyll::Page which will act as the pager template
72
+ def template_page(site)
73
+ site.pages.dup.select do |page|
74
+ Pager.pagination_candidate?(site.config, page)
75
+ end.sort do |one, two|
76
+ two.path.size <=> one.path.size
77
+ end.first
78
+ end
79
+ end
80
+ end
81
+
82
+ class Pager
83
+ attr_reader :page, :per_page, :posts, :total_posts, :total_pages,
84
+ :previous_page, :previous_page_path, :next_page, :next_page_path
85
+
86
+ # Calculate the number of pages.
87
+ #
88
+ # all_posts - The Array of all Posts.
89
+ # per_page - The Integer of entries per page.
90
+ #
91
+ # Returns the Integer number of pages.
92
+ def self.calculate_pages(all_posts, per_page)
93
+ (all_posts.size.to_f / per_page.to_i).ceil
94
+ end
95
+
96
+ # Determine if pagination is enabled the site.
97
+ #
98
+ # site - the Jekyll::Site object
99
+ #
100
+ # Returns true if pagination is enabled, false otherwise.
101
+ def self.pagination_enabled?(site)
102
+ !site.config['paginate'].nil? &&
103
+ site.pages.size > 0
104
+ end
105
+
106
+ # Static: Determine if a page is a possible candidate to be a template page.
107
+ # Page's name must be `index.html` and exist in any of the directories
108
+ # between the site source and `paginate_path`.
109
+ #
110
+ # config - the site configuration hash
111
+ # page - the Jekyll::Page about which we're inquiring
112
+ #
113
+ # Returns true if the
114
+ def self.pagination_candidate?(config, page)
115
+ page_dir = File.dirname(File.expand_path(remove_leading_slash(page.path), config['source']))
116
+ paginate_path = remove_leading_slash(config['paginate_path'])
117
+ paginate_path = File.expand_path(paginate_path, config['source'])
118
+ page.name == 'index.html' &&
119
+ in_hierarchy(config['source'], page_dir, File.dirname(paginate_path))
120
+ end
121
+
122
+ # Determine if the subdirectories of the two paths are the same relative to source
123
+ #
124
+ # source - the site source
125
+ # page_dir - the directory of the Jekyll::Page
126
+ # paginate_path - the absolute paginate path (from root of FS)
127
+ #
128
+ # Returns whether the subdirectories are the same relative to source
129
+ def self.in_hierarchy(source, page_dir, paginate_path)
130
+ return false if paginate_path == File.dirname(paginate_path)
131
+ return false if paginate_path == Pathname.new(source).parent
132
+ page_dir == paginate_path ||
133
+ in_hierarchy(source, page_dir, File.dirname(paginate_path))
134
+ end
135
+
136
+ # Static: Return the pagination path of the page
137
+ #
138
+ # site - the Jekyll::Site object
139
+ # num_page - the pagination page number
140
+ #
141
+ # Returns the pagination path as a string
142
+ def self.paginate_path(site, num_page)
143
+ return nil if num_page.nil?
144
+ return Generators::Pagination.first_page_url(site) if num_page <= 1
145
+ format = site.config['paginate_path']
146
+ format = format.sub(':num', num_page.to_s)
147
+ ensure_leading_slash(format)
148
+ end
149
+
150
+ # Static: Return a String version of the input which has a leading slash.
151
+ # If the input already has a forward slash in position zero, it will be
152
+ # returned unchanged.
153
+ #
154
+ # path - a String path
155
+ #
156
+ # Returns the path with a leading slash
157
+ def self.ensure_leading_slash(path)
158
+ path[0..0] == "/" ? path : "/#{path}"
159
+ end
160
+
161
+ # Static: Return a String version of the input without a leading slash.
162
+ #
163
+ # path - a String path
164
+ #
165
+ # Returns the input without the leading slash
166
+ def self.remove_leading_slash(path)
167
+ ensure_leading_slash(path)[1..-1]
168
+ end
169
+
170
+ # Initialize a new Pager.
171
+ #
172
+ # site - the Jekyll::Site object
173
+ # page - The Integer page number.
174
+ # all_posts - The Array of all the site's Posts.
175
+ # num_pages - The Integer number of pages or nil if you'd like the number
176
+ # of pages calculated.
177
+ def initialize(site, page, all_posts, num_pages = nil)
178
+ @page = page
179
+ @per_page = site.config['paginate'].to_i
180
+ @total_pages = num_pages || Pager.calculate_pages(all_posts, @per_page)
181
+
182
+ if @page > @total_pages
183
+ raise RuntimeError, "page number can't be greater than total pages: #{@page} > #{@total_pages}"
184
+ end
185
+
186
+ init = (@page - 1) * @per_page
187
+ offset = (init + @per_page - 1) >= all_posts.size ? all_posts.size : (init + @per_page - 1)
188
+
189
+ @total_posts = all_posts.size
190
+ @posts = all_posts[init..offset]
191
+ @previous_page = @page != 1 ? @page - 1 : nil
192
+ @previous_page_path = Pager.paginate_path(site, @previous_page)
193
+ @next_page = @page != @total_pages ? @page + 1 : nil
194
+ @next_page_path = Pager.paginate_path(site, @next_page)
195
+ end
196
+
197
+ # Convert this Pager's data to a Hash suitable for use by Liquid.
198
+ #
199
+ # Returns the Hash representation of this Pager.
200
+ def to_liquid
201
+ {
202
+ 'page' => page,
203
+ 'per_page' => per_page,
204
+ 'posts' => posts,
205
+ 'total_posts' => total_posts,
206
+ 'total_pages' => total_pages,
207
+ 'previous_page' => previous_page,
208
+ 'previous_page_path' => previous_page_path,
209
+ 'next_page' => next_page,
210
+ 'next_page_path' => next_page_path
211
+ }
212
+ end
213
+ end
214
+ end